2015-05-26 6 views
16

Vorrei trasformare la seguente lista di tupleZippare stesso valore su una lista di tuple Haskell

a = [(1,()),(2,())] 

in un elenco tupla nidificato per lo stesso valore

b = [(False,(1,())),(False,(2,()))] 

Utilizzando la funzione di cerniera in questo formato

zip [False] a 

mi dà solo

[(False,(1,()))] 

Qualsiasi suggerimento o consiglio sarebbe molto apprezzato.

+6

Perché usare 'zip' quando si ha' map'? – AJFarmar

+0

'f = (<$>). (,) ' – Shanthakumar

risposta

33

Se si zip due elenchi di lunghezze diverse, si ottiene la lunghezza dell'elenco più breve.

È possibile risolvere questo problema zippare contro un infinitamente lungo lista:

zip (repeat False) a 

dovrebbe fare il trucco.

29

In alternativa, invece di usare zip è possibile utilizzare map:

map (\x -> (False, x)) a 

questo sarebbe più appropriato esprimere il vostro intento (a mio parere), in quanto si vuole fare la stessa cosa ad ogni elemento della lista. Se vuoi fare cose diverse per ogni elemento, allora zip o zipWith potrebbe essere più appropriato.

Se si voleva evitare il lambda, è possibile scrivere pointfree usando &&& da Control.Arrow:

map (const False &&& id) a 

che in pratica dice "si applicano le funzioni const False e id all'ingresso, poi costruire una tupla di entrambi le loro uscite ". C'è il TupleSections estensione che permetterebbe di scrivere questo come

map (False,) a 

(suggerimento fornito da @thoferon), ma io personalmente trovare questo meno chiaro, dal momento che si deve sapere che l'estensione è attivato e notare la , dopo False. Si potrebbe scrivere come

map ((,) False) a 

senza l'estensione dal (,) agisce in funzione del tipo di a -> b -> (a, b), e mentre un po 'più dettagliato non richiede che permette un'estensione del linguaggio.

+4

Oppure con TupleSections:' map (False,) a' – thoferon

+0

@thoferon Certamente, ma in questo caso direi onestamente che sarebbe meno chiaro. La differenza tra 'map (False,) a' e' map (False) a' è solo 1 carattere, e quel personaggio è molto importante. Preferirei avere 'map (const False &&& id)' usando 'Control.Arrow' se dovessi andare senza punti. Non richiede estensioni ed è un codice molto chiaro (purché tu sappia cosa '&&&' fa). Considerando che ciò richiede un'importazione e molti altri caratteri, non mi dispiace un Lambda puntuale per questo semplice caso. – bheklilr

+1

Utilizzando una freccia qui e non la versione di thoferon è semplicemente sciocco. Anche il tuo ultimo suggerimento (in notazione prefisso) è buono. –

6

Oltre ad altre risposte è anche possibile scrivere una funzione generica per qualsiasi Functor, non solo per le liste:

strengthL :: Functor f => a -> f b -> f (a, b) 
strengthL = fmap . (,) 

strengthR :: Functor f => a -> f b -> f (b, a) 
strengthR = fmap . flip (,) 

Poi strengthL può essere applicato su False e la lista originale:

Prelude> strengthL False [(1,()),(2,())] 
[(False,(1,())),(False,(2,()))]