2010-12-29 14 views
32

Esiste un modo in Haskell per associare il secondo argomento ma non il primo di una funzione senza utilizzare le funzioni lambda o definire un'altra funzione "locale"?Come posso associare il secondo argomento in una funzione ma non il primo (in modo elegante)?

Esempio. Ho una funzione binaria come:

sub :: Int -> Int -> Int 
sub x y = x - y 

Ora, se voglio legare il primo argomento, posso farlo facilmente usando (sub someExpression):

mapSubFrom5 x = map (sub 5) x 

*Main> mapSubFrom5 [1,2,3,4,5] 
[4,3,2,1,0] 

Questo funziona bene se voglio legare i primi n argomenti senza "gap".

Se voglio legare il secondo argomento, ma non il primo, le due opzioni sono a conoscenza sono più prolisso:

sia tramite un altro, locali, funzione:

mapSub5 x = map sub5 x 
    where sub5 x = sub x 5 

*Main> mapSub5 [1,2,3,4,5] 
[-4,-3,-2,-1,0] 

o utilizzando lambda :

mapSub5 x = map (\x -> sub x 5) x 

Mentre entrambi stanno lavorando bene, mi piace l'eleganza della "sub 5" e mi chiedo se c'è un modo simile eleganza di impegnare la n-esimo (n> 1) argomento di una funzione?

risposta

28

flip, che produce una nuova funzione con i primi due argomenti invertita, è già stato menzionato come soluzione straigtforward.

Tuttavia, vale la pena notare che Haskell definisce una bella sintassi infix per gli operatori binari.

Prima di tutto, è semplicemente

sub = (-) 

Con parentesi attorno, tutti gli operatori sono - syntactially troppo - funzioni ordinarie. Ora possiamo eseguire il curry degli operatori con una sintassi speciale. Il legame con il primo operando:

addOne = (1 +) 

... e alla seconda

half = (/ 2) 

Così il codice diventa

map (-5) [1..5] 

Purtroppo, -5 è un numero letterale, ma si ottiene la punto.:) Ora, poiché siamo in grado di trasformare qualsiasi funzione in un operatore binario mettendo backticks intorno ad esso come in

f x y == x `f` y 

possiamo usare questa sintassi speciale all'operatore di scrivere

map (`sub` 5) [1..5] 


Nota: Currying il primo argomento è comune, il secondo - come nel tuo caso - ben fatto. Ma: non lo farei per argomenti futher. Le funzioni di Haskell sono scritte in uno stile che i comuni di curry sono nella parte anteriore esattamente per questa ragione.

L'utilizzo di alcune sintassi speciali per ulteriori argomenti mi sembra troppo implicito per me. Basta usare il lambda e dare i nomi descrittivi delle variabili.

+12

Poiché '-5' è un numero, i creatori di haskell hanno persino aggiunto una funzione' sottrazione' che è definita come 'sottrazione = flip (-)' in modo da poter scrivere 'map (sottrarre 5)'. È più leggibile, però. – fuz

+3

Inoltre, un corollario alla nota finale: se si desidera applicare in modo parziale argomenti successivi a una funzione scritta dall'utente, non esitate a modificare direttamente l'ordine! È relativamente raro che una funzione abbia tre o più argomenti che sono tutti probabilmente utilizzati in questo modo. –

7

Come associare il secondo argomento:

div2 = flip div 2 

ghci> div2 10 
5 

Nel tuo caso è possibile scrivere

ghci> map (flip (-) 5) [1..5] 
[-4,-3,-2,-1,0] 

Si noti che in Haskell è possibile scrivere gli operatori in forma prefisso (-). È lo stesso di sub nella tua domanda.

+0

(So di (-). Sub era solo una funzione di esempio primitivo) Grazie per indicare di capovolgere. Questo funziona almeno per il caso del secondo argomento. Anche se credo di trovare il più verboso in cui i modi/lambda sono più leggibili. –

8

Per n = 2 solo un altro modo per impegnare:

mapSub5 x = map (`sub` 5) x 
Problemi correlati