2015-12-23 15 views
6

Non mi è chiaro il motivo per cui la funzione definita comeTipo di f g x = g. gx

f g x = g . g x 

ha il tipo

f :: (b -> a -> b) -> b -> a -> a -> b 

avrei pensato che sarebbe stato di tipo

f :: (t -> t) -> t -> t 

Qualcuno può spiegare per me come si decompone l'espressione? Grazie!

risposta

11

Si noti che l'applicazione di funzione ha la priorità più alta; gli operatori vengono dopo.

Quindi, il termine g . g x prima si applica g-x, e quindi compone il risultato e g stessa. Se x ha il tipo b, g deve avere il tipo b -> c. Poiché componiamo g con g x (quest'ultimo di tipo c), c deve essere un tipo di funzione che restituisce b, così c = a -> b. Ora il tipo di g è b -> a -> b e il tipo di g . g x è a -> (a -> b); il tipo di f risulta essere (b -> a -> b) -> b -> a -> a -> b.

Se si voleva qualcosa di simile (a -> a) -> a -> a, invece, si potrebbe provare uno di questo

f g x = g (g x) 
f g x = (g . g) x 
f g x = g . g $ x 
f g = g . g 
+0

in modo da ottenere che g è di tipo (b -> a -> b), ma poi come faccio a dedurre il tipo di g. g x? – SendMeMemes

+0

@SendMeMemes controlla la firma dell'operatore di composizione '(y -> z) -> (x -> y) -> x -> z' e confrontalo con i tipi dei suoi argomenti:' g' e 'g x'. – lisyarus

2

L'idea è di capire l'operatore (.), ha un tipo di

(.) :: (b -> c) -> (a -> b) -> a -> c 

Ci vogliono due funzioni ciascuno con uno parametro e li compongono, dopo l'applicazione g x il compilatore presume g è in realtà g :: a -> b -> c per soddisfare la firma di (.) :: (b -> c) -> (a -> b) -> a -> c che accetta due funzioni con un argomento. Altrimenti il ​​codice non verrà compilato.

E, infine, se si desidera che la firma f :: (t -> t) -> t -> t avete bisogno di qualcosa di simile:

λ> let applyTwice g = g.g 
λ> :t applyTwice 
applyTwice :: (a -> a) -> a -> a 
λ> applyTwice (*2) 3 
12