6

OK, è stata una lunga giornata e il mio cervello potrebbe non funzionare a livello Haskell, ma non riesco proprio a capire un esempio di "Learn You a Haskell".Applicazione funzione in Haskell

La sezione si chiama Applicazione Funzione con $, e non v'è esempio di come può essere definita $:

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

Finora tutto è chiaro. Capisco tutti gli esempi nella sezione, tranne che per l'ultimo:

ghci> map ($ 3) [(4+), (10*), (^2), sqrt] 
[7.0,30.0,9.0,1.7320508075688772] 

Qui map ($ 3) tutta elenco delle funzioni e ottenere il risultato di applicazione di dette funzioni a 3. Ma come è possibile?

Dal primo frammento di codice è chiaro che il primo argomento è una funzione, possiamo anche scrivere:

*Main> ($) sqrt 4 
2.0 

Ora ($ 3) è un'applicazione parziale della funzione $, ma 3 va sulla posizione di funzione! Quindi 3 dovrebbe essere una funzione o cosa?

C'è un altro mistero: che diamine è (4+)? So che (+4) è un'applicazione parziale della funzione +, quindi (4+) dovrebbe essere l'applicazione parziale della funzione 4? Senza senso. Che tipo di trucco funziona qui?

+0

possibile duplicato di [Applicazione parziale con funzioni Infix] (http://stackoverflow.com/questions/10131300/partial-application-with-infix-functions) – Lambdageek

risposta

12

($ 3) e (+ 4) non sono applicazioni parziali - sono sezioni operatore. Un'applicazione parziale apparirebbe come (($) 3) o ((+) 4).

Una sezione operatore della forma (? x) (dove ? sta per un operatore infisso arbitrario) lega il destra operando dell'operatore, cioè è equivalente a \y -> y ? x.Allo stesso modo, la sezione operatore (x ?) collega l'operando di sinistra ed è quindi equivalente all'applicazione parziale.

6

Penso che quello che ti ha inciampato è sezioni operatore. Questi consentono di applicare parzialmente un operatore con uno dei suoi argomenti, in modo da poter disporre degli operatori (+4) e (4+), dove 4 è il secondo il primo argomento rispettivamente a +. Un esempio più chiaro potrebbe essere ("Hello" ++) versus (++ "world"), il precedente antepone "Hello" sul lato anteriore di una stringa, mentre il secondo aggiunge "world" alla fine di una stringa.

Questo è in contrasto con l'utilizzo di operatori in forma di prefisso con solo parenti intorno ad esso. In questa forma, i seguenti sono equivalenti:

> let join = (++) 
> join "Hello, " "world" 
"Hello, world" 
> (++) "Hello, " "world" 
"Hello, world" 

in forma prefisso, si trattano l'operatore in funzione normale ed accetta il suo primo poi secondo argomento in ordine. Nelle sezioni operatore, è importante su quale lato dell'argomento si trova l'argomento.


Quindi nel tuo esempio, si ha l'applicazione parziale della ($ 3), è possibile ridurre il più

map ($ 3) [(4+), (10*), (^2), sqrt] 
[($ 3) (4+), ($ 3) (10 *), ($ 3) (^ 2), ($ 3) sqrt] 
[4 + 3, 10 * 3, 3^2, sqrt 3] 
[7.0, 30.0, 9.0, 1.7320508075688772] 
+0

"si considera l'operatore come una funzione normale", ho pensato che "operatori" * sono * funzioni normali in Haskell. – Mark

+1

@ Mark sono normali sotto ogni aspetto tranne la loro sintassi per l'applicazione. Sono per impostazione predefinita, mentre una funzione non operatore è predefinita come prefisso. Quando dico funzione normale, intendo una funzione prefisso. – bheklilr

4

Ti stai confondendo con le sezioni. Un buon modo per afferrare il concetto di sezioni sta giocando con un esempio:

(<^>) :: Int -> Float -> Int 
a <^> b = a 

La funzione di cui sopra è una funzione inutile che restituisce il primo parametro non importa quale il secondo parametro è. Ma accetta Int e quindi Float come input.

Ora, a causa di sezioni è possibile applicare con uno qualsiasi dei loro argomenti:

λ> let a = (3 <^>) 
λ> :t a 
a :: Float -> Int 
λ> let b = (<^> 3.0) 
λ> :t b 
b :: Int -> Int 

vedere come il tipo di a e b sono diversi a causa di sezioni.