2013-04-03 18 views
8

So

$ :: (a->b) -> a -> b 
f $ x = f x 

Intuitivamente mi sembra, come a dire, 1. $ ritarda la valutazione della funzione alla sua sinistra 2. valuta che cosa è alla sua destra 3. alimenta il risultato della sua lasciato alla sua destra.

Ed ha perfettamente senso per me quando,

ghci> length $ [1..5] 
5 
ghci> ($) length [1..5] 
5 

Quello che non capisco è il motivo per cui,

ghci> ($ [1..5]) length 
5 

A giudicare dal tipo di $, non è che il suo (primo) argomento dovrebbe essere una funzione?

+13

Non si tratta di '($)', ma di sezioni dell'operatore. – phg

+9

'$' * non * ritarda la valutazione della funzione a sinistra. Potresti confonderla con '$!', Che forza la valutazione parziale dell'argomento alla sua destra prima di alimentarla alla funzione alla sua sinistra. – dave4420

+0

Questa è la sintassi della "sezione" al lavoro. http://www.haskell.org/onlinereport/haskell2010/haskellch3.html#x8-300003.5 –

risposta

15

Questo ha a che fare con l'analisi. In Haskell puoi scrivere (op arg) dove op è un operatore infisso. Questo non è lo stesso di ((op) arg). E puoi anche scrivere (arg op)! Ad esempio:

GHCi, version 7.0.3: http://www.haskell.org/ghc/ :? for help 
Prelude> :t (+ 4) 
(+ 4) :: Num a => a -> a 
Prelude> :t (4 +) 
(4 +) :: Num a => a -> a 

Cioè, (+ 4) è la funzione \x -> x + 4 e (4 +) è la funzione \y -> 4 + y. Nel caso di aggiunta, queste sono funzioni uguali, ma al momento non è molto importante.

Ora proviamo lo stesso trucco su $:

Prelude> :t ($ [1,2,3,4]) 
($ [1,2,3,4]) :: Num t => ([t] -> b) -> b 

Ora sorpresa finora, abbiamo ottenuto \f -> f $ [1,2,3,4]. Possiamo anche scrivere

Prelude> :t (length $) 
(length $) :: [a] -> Int 

per ottenere la funzione \l -> length $ l. Ma che dire di questo:

Prelude> :t ($ length) 
($ length) :: (([a] -> Int) -> b) -> b 

Questo è strano, ma ha senso! Abbiamo ottenuto \f -> f $ length, ad es., un funzionale che si aspetta di ottenere una funzione f di tipo ([a] -> Int) -> b) che verrà applicata a length. C'è una quarta possibilità:

Prelude> :t ([1,2,3,4] $) 

<interactive>:1:2: 
    Couldn't match expected type `a0 -> b0' with actual type `[t0]' 
    In the first argument of `($)', namely `[1, 2, 3, 4]' 
    In the expression: ([1, 2, 3, 4] $) 

Tutto è come dovrebbe essere perché [1,2,3,4] non è una funzione. Cosa succede se scriviamo $ tra parentesi? Poi il suo significato speciale come un operatore infisso scompare:

Prelude> :t (($) length) 
(($) length) :: [a] -> Int 

Prelude> :t (($) [1,2,3,4]) 
<interactive>:1:6: 
    Couldn't match expected type `a0 -> b0' with actual type `[t0]' 
    In the first argument of `($)', namely `[1, 2, 3, 4]' 
    In the expression: (($) [1, 2, 3, 4]) 

Prelude> :t (length ($)) 
<interactive>:1:9: 
    Couldn't match expected type `[a0]' 
       with actual type `(a1 -> b0) -> a1 -> b0' 
    In the first argument of `length', namely `($)' 
    In the expression: (length ($)) 

Prelude> :t ([1,2,3,4] ($)) 
<interactive>:1:2: 
    The function `[1, 2, 3, 4]' is applied to one argument, 
    but its type `[t0]' has none 
    In the expression: ([1, 2, 3, 4] ($)) 

Quindi, per rispondere alla tua domanda: $ [1,2,3,4] viene analizzato come \f -> f $ [1,2,3,4] quindi ha senso perfetto per applicarlo al length. Tuttavia, ($) [1, 2, 3, 4] non ha molto senso perché ($) non è visto come un operatore infisso.

A proposito, lo "$" non fa nulla ", per così dire. Viene utilizzato principalmente per l'input più leggibile perché ha una precedenza bassa e quindi è possibile scrivere f $ g $ h $ x anziché f (g (h x)).

+1

'-' potrebbe essere una cattiva scelta di esempio, in quanto è l'unica eccezione dove' (op arg) 'does * not * rappresenta una funzione. –

+1

Inoltre, entrambi '((-) 4)' e '(4 -)' sono la stessa funzione, '(\ x -> 4 - x)'. –

+0

Significa che (-) è associato, entrambi ((-) 4) e (4 -) significa (\ x -> 4 - x), mentre ($) è associato a destra, entrambi ($ func) e ($ arg) significa (\ x -> bar $ a) dove a significa func o arg? – Znatz

10

La tua domanda è davvero di quello che viene chiamato sezioni operatore. Con qualsiasi operatore in Haskell (userò + come esempio) è possibile scrivere qualcosa come (+ arg) o (arg +). Queste sono solo sintassi abbreviata per le funzioni anonime (\x -> x + arg) e (\x -> arg + x), rispettivamente.

Quindi, la sintassi ($ [1..5]) significa semplicemente (\x -> x $ [1..5]) che è lo stesso come (\x -> x [1..5]) (es. Una funzione che passa [1..5] alla funzione passata come argomento).

+0

Questo (\ x -> x $ [1..5]) chiarisce davvero la mia confusione! – Znatz

Problemi correlati