2010-07-04 12 views
18

Quale dei seguenti è più probabile scrivere?Haskell map/zip vs. list comprehension

r = zip xs $ map sqrt xs 

o

r = [(x, sqrt x) | x <- xs] 

codice di esempio su Internet sembra indicare che il primo è più abbondante e il modo preferito.

risposta

9

avrei probabilmente scrivo

map (\x -> (x, sqrt x)) xs 

Se si preferisce senza punti, quanto sopra è equivalente a (dopo aver importato Control.Monad e Control.Monad.Instances)

map (ap (,) sqrt) xs 

Un'altra alternativa che hasn' t ancora menzionato è

zipWith (,) xs (map sqrt xs) 
6

Uso raramente le list comprehensions, ma entrambe sono dandy. Basta usare quello che rende il tuo codice più facile da leggere.

23

Le persone che trascorrono troppo tempo in #haskell probabilmente scrivono che come

r = map (id &&& sqrt) xs 

(&&&) è un combinatore divertente definito Control.Arrow. La sua vera firma di tipo è complicata perché è generalizzata a tutte le istanze di Arrow. Ma è spesso utilizzato con la (->) istanza di Arrow, che si traduce in questa firma tipo:

(&&&) :: (a -> b) -> (a -> c) -> a -> (b, c) 
+7

Mi riferisco a questo come "opaco hakell". Ad un certo punto è appena illeggibile, il punto varia a seconda dell'esposizione. – Dan

+1

In effetti, tendo a definire una funzione che, per mancanza di un nome migliore, chiamo 'preserving :: (a -> b) -> a -> (a, b)', definita semplicemente 'preserving = (id &&&) '. (A volte cambio anche l'ordine della tupla e lo definisco come '(&& & id)'; dovrei essere coerente.) Sono sempre un po 'sorpreso dal fatto che non sembra uscire da qualsiasi standard. –

+8

Dan, penso che sia probabilmente il più facile Combinatore di frecce da usare in codice reale Il suo nome è piacevolmente evocativo: puoi leggere quella riga di codice ad alta voce come "ID mappa e sqrt a xs". – Carl

15

Anche se tendo a non usarli per molto spesso, in questo caso, penso che preferirei la versione di lista, dal momento che sembra più pulito per me.

Se siete in free style punto, come si potrebbe anche questa:

f = zip `ap` map sqrt 

AP vive in Control.Monad e in questo caso, può essere pensato come la Combinator S, che generalizza applicazione in SKI calculus:

ap f g x == f x (g x) 
ap const const == id 

Come Conal sottolinea, questo può anche essere generalizzata da Monade a questa convenzione applicativa (importazione Control.Applicative):

f = zip <*> map sqrt 
+1

carino, mi piace la notazione migliore. Ho sempre letto 'ap' come" apply ", quindi diventa:" zip applica map con sqrt per inserire " – Dan

+2

Oppure, semplificando/generalizzando da' Monad' a 'Applicativo',' f = zip <*> map sqrt'. Anche se personalmente preferisco 'map (id &&& sqrt) xs' come nella risposta di carl. – Conal

+0

Sì, questo è IMHO un bel modo per leggerlo. @Conal ha aggiunto il tuo suggerimento alla risposta. Le frecce – danlei

11

Probabilmente scriverei map/zip e successivamente vorrei aver scritto la comprensione della lista.

9

Per alcuni tipi di problemi (Project Euler in particolare), questo caso particolare viene così spesso che ho scritto il seguente piccolo aiutante:

with :: (a -> b) -> a -> (a,b) 
with f a = (a, f a) 

In questo modo il vostro esempio da scrivere:

r = map (with sqrt) xs 
6

Sono più di un "Old School" Haskellier, quindi userei zip `ap` map sqrt e successivamente lo refactero per usare il <*> invece di ap.

Applicativo è la nuova Monade. (Nel senso di "cosa usano i Cool Haskell Kids in questi giorni?")

+3

sono la nuova monade, no? –