2014-11-20 15 views
6

Leggere "Pensare in modo funzionale con Haskell" Mi sono imbattuto in una parte di un calcolo del programma che richiedeva la riscrittura di map sum (map (x:) xss) come map (x+) (map sum xss)Haskell - Come trasformare la somma della mappa (mappa (x :) xss) per mappare (x +) (somma mappa xss)

Intuitivamente so che ha un senso ...

se si dispone di alcune liste che si sta per sommare, ma, prima di sommare, a quelle stesse liste si stanno anche per aggiungere un elemento 'x ', quindi equivale a prendere una lista di somme delle liste orignali e ad aggiungere il valore di x a ciascuna di esse.

Ma mi piacerebbe sapere come trasformare l'uno nell'altro solo usando il ragionamento equazionale. Mi sento come se mi mancasse una legge o una regola che mi aiuterebbe a capire.

risposta

12

Utilizzando la legge

map f (map g list) === map (f . g) list 

Possiamo dedurre

map sum (map (x:) xss) = 
map (sum . (x:)) xss = 

eta-espandere per dare un argomento di lavorare con

map (\xs -> sum . (x:) $ xs) xss = 

Sostituendo per (f . g) x === f (g x)

map (\xs -> sum (x:xs)) xs = 

Dove

sum (x:xs) = x + sum xs 
sum [] = 0 

così

map (\xs -> sum (x:xs)) xss = 
map (\xs -> x + sum xs) xss = 

Sostituendo f (g x) === (f . g) x

map (\xs -> (x +) . sum $ xs) xss = 

eta-ridurre il lambda

map ((x +) . sum) xss = 

Utilizzare il retro della prima legge dall'alto

map (x+) (map sum xss) 
+0

Non sono d'accordo sulla comprensione dell'elenco, ma è certamente una questione di gusti. Perché non usare la definizione di '(.)' E dire 'map (sum. (X :)) xss = map (\ xs -> sum (x: xs)) xss = map (\ xs -> x + sum xs) = ... '? – kosmikus

+0

@kosmikus Eh, gusto personale. In questo caso è piuttosto irrilevante, ma potrei vedere l'argomento per tenere 'map' lì dentro per tutto il tempo. – bheklilr

+0

@kosmikus ha un aspetto migliore? – bheklilr

0

Ti consiglio di guardare i tipi e lasciarli guidare attraverso la trasformazione.

> let xss = [[1], [2], [3]] 
> :t xss 
xss :: Num t => [[t]] 
> map sum xss  -- basically compacting the lists 
[1,2,3] 
> :t map sum xss -- into just a list of numbers 
map sum xss :: Num b => [b] 

Poi abbiamo bisogno di fare l'aggiunta

> :t (+5) 
(+5) :: Num a => a -> a 
> :t map (+5)  -- no magic in this 
map (+5) :: Num b => [b] -> [b] 
> map (+5) (map sum xss) 
[6,7,8] 

La linea di fondo Direi è che nel primo esempio si sta modificando i tipi nella altro modo se non nella seconda. Il punto in cui una lista di liste diventa solo una lista cambia, così come il modo in cui aggiungi il numero.