2010-06-26 14 views
13

Ho giocato un po 'con Haskell, compreso esercitarsi a scrivere in forma senza punti. Ecco una funzione di esempio:Perché la versione pointfree di questa funzione è simile a questa?

dotProduct :: (Num a) => [a] -> [a] -> a 
dotProduct xs ys = sum (zipWith (*) xs ys) 

Vorrei scrivere questa funzione in forma senza punti. Ecco un esempio che ho trovato altrove:

dotProduct = (sum .) . zipWith (*) 

Tuttavia, non capisco il motivo per cui la forma libera-punto sembra (sum .) . zipWith (*) invece di sum . zipWith (*). Perché la somma è tra parentesi e ha 2 operatori di composizione?

risposta

19
dotProduct xs ys = sum (zipWith (*) xs ys)    -- # definition 

dotProduct xs = \ys -> sum (zipWith (*) xs ys)  -- # f x = g <=> f = \x -> g 
       = \ys -> (sum . (zipWith (*) xs)) ys -- # f (g x) == (f . g) x 
       = sum . (zipWith (*) xs)    -- # \x -> f x == f 
       = sum . zipWith (*) xs    -- # Precedence rule 

dotProduct  = \xs -> sum . zipWith (*) xs   -- # f x = g <=> f = \x -> g 
       = \xs -> (sum .) (zipWith (*) xs)  -- # f * g == (f *) g 
       = \xs -> ((sum .) . zipWith (*)) xs -- # f (g x) == (f . g) x 
       = (sum .) . zipWith (*)    -- # \x -> f x == f 

Il (sum .) è una sezione. È definito come

(sum .) f = sum . f 

Qualsiasi operatore binario può essere scritto in questo modo, ad es. map (7 -) [1,2,3] == [7-1, 7-2, 7-3].

+0

Il '*' in questa parte 'f * g == (f *) g' è uguale alla composizione della funzione' .'? – guhou

+0

@Bleu: Sì. Qualsiasi operatore binario farà. – kennytm

13

risposta di KennyTM è eccellente, ma ancora vorrei offrire un altro punto di vista:

dotProduct = (.) (.) (.) sum (zipWith (*)) 
  • (.) f g vale f sul risultato di g dato un argomento
  • (.) (.) (.) f g applica f sul risultato di g dato due argomenti
  • (.) (.) ((.) (.) (.)) f g si applica f sul risultato di g dato tre argomenti
  • ...
  • può fare (.~) = (.) (.) (.), (.~~) = (.) (.) (.~), (.~~~) = (.) (.) (.~~) ed ora let foo a b c d = [1..5]; (.~~~) sum foo 0 0 0 0 risultati in 15.
    • Ma non lo farei. Probabilmente renderà il codice illeggibile. Basta essere puntuali.
  • Conal di TypeCompose fornisce un sinonimo di (.) chiamato result. Forse questo nome è più utile per capire cosa sta succedendo.
    • fmap funziona anche al posto di (.), se l'importazione delle istanze competenti (import Control.Applicative sarebbe farlo), ma il suo tipo è più generale e, quindi, forse più confuso.
  • Il concetto di Conal di "fusione" (da non confondere con altri usi di "fusione") è un po 'correlato e imho offre un buon modo per comporre le funzioni. Maggiori dettagli in this long Google Tech Talk that Conal gave
+0

Grazie per la risposta! Sono ancora abbastanza nuovo con Haskell, quindi alcuni di questi sembrano ... incisivi .. ma anche apprendere approcci diversi è utile :) – guhou

+2

Il caso '(.) (.) (.)' È abbastanza comune e semplice che io a volte crea un '(...) Operatore per esso. Oltre a questo, però, è probabilmente il momento di essere puntuali. –

+1

troppo cattivo '..' è preso: D –

Problemi correlati