2013-03-12 10 views
10

Sto cercando di comprendere l'operatore dell'applicazione di funzione ($) in Haskell.Cercando di capire l'operatore dell'applicazione di funzione in Haskell

sto lavorando attraverso gli esempi in Learn È un Haskell, e ho pensato ho capito il seguente esempio:

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

Allora ho provato la seguente variante, che ha anche lavorato bene:

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

Infine, ho provato modificando la terza funzione nell'elenco come segue, che genera un errore:

Prelude> map ($ 3) [(+4), (*10), (\x -> 2^x), sqrt] 
<interactive>:53:38: 
    Ambiguous type variable `b0' in the constraints: 
     (Floating b0) 
     arising from a use of `sqrt' at <interactive>:53:38-41 
     (Integral b0) arising from a use of `^' at <interactive>:53:33 
     (Num b0) arising from the literal `3' at <interactive>:53:8 
    Probable fix: add a type signature that fixes these type variable(s) 
    In the expression: sqrt 
    In the second argument of `map', namely 
     `[(+ 4), (* 10), (\ x -> 2^x), sqrt]' 
    In the expression: map ($ 3) [(+ 4), (* 10), (\ x -> 2^x), sqrt] 
Prelude> 
.210

Sembra se la funzione finale è in qualche modo sqrt iniziano associato all'elemento precedente elenco, come la seguente variante funziona bene:

Prelude> map ($ 3) [(+4), (*10), (\x -> 2^x)] 
[7,30,8] 

Qualcuno può illuminarmi su ciò che sta succedendo qui?

+0

una lezione da prendere da questo, dopo aver provato qualcosa al prompt GHCi, controllare il suo * tipo *, con ** 'Prelude>: t it' **. "It" è una parola speciale, riferita al risultato precedente, e ': t' chiede di vedere un tipo. È possibile vedere che non ci sono punti decimali nei numeri nel tuo ultimo esempio. Inoltre, dopo aver inserito **:: s + t' ** al prompt, il GHCi riporterà il tipo per ogni risultato che produce. –

risposta

17

Il tipo di operatore esponenziale utilizzato è

(^) :: (Num a, Integral b) => a -> b -> a 

in modo che quando si utilizza \x -> 2^x, si ottiene un vincolo Integral per la 3. Ma sqrt impone un vincolo Floating. Così il tipo di 3 deve soddisfare

3 :: (Integral t, Floating t) => t 

ma non v'è alcuna istanza sia nella lista tipo di default, che è Integer e Double, in modo che l'inadempiente non riesce e si è lasciato con una variabile di tipo ambiguo.

Quando hai avuto \x -> x^2, c'era solo un vincolo Num dalle prime funzioni, e Floating da sqrt, in modo che il tipo è stato stabilizzato a Double.

È possibile farlo funzionare se si utilizza

(**) :: Floating a => a -> a -> a 

come l'operatore di elevamento a potenza, quindi il tipo può essere nuovamente in default a Double.

+3

Quindi potrebbe ripararlo, sostituendo (^) con (**). – zurgl

+0

Grazie a Daniel e Zurgl - che chiarisce le cose in modo considerevole. Venendo da Python sto ancora avvolgendo la mia mente sulle implicazioni del rigoroso controllo dei tipi. –

Problemi correlati