2015-11-08 23 views
9

Vengo dalla Scala. Così ho spesso fare cose come:Metodi di concatenamento da sinistra a destra in Haskell (opposto a destra a sinistra)

println((1 to 10).filter(_ < 3).map(x => x*x)) 

In Haskell, dopo ho scoperto che posso liberarmi di tutte le parentesi nidificate utilizzando $ e ., di recente ho trovato a scrivere:

putStrLn . show . map (**2) . filter (< 3) $ [1..10] 

Ora, questo funziona, ma il codice si legge da destra a sinistra e, a meno che non mi sposti in arabo, per me è difficile ragionare.

C'è qualche altro trucco che mi fa incatenare le funzioni da sinistra a destra? O questo è solo il modo idiomatico di Haskell?

+1

Si noti che 'putStrLn. mostra = stampa'. Inoltre, potresti usare 'mapM' o' forM': 'forM [x | x <- [1..10], x <3] $ stampa. (** 2) 'o qualcosa di simile. – Bakuriu

+0

Una volta che ci si abitua, da sinistra a destra è più facile ragionare: ti dà il tipo di espressione. Nel tuo caso 'putStrnLn ... 'So che è un IO. – mb14

+1

Osservazione non utile: il 'flusso' della normale applicazione concatenata (senza usare la composizione della funzione) è da destra a sinistra: 'f. g. h $ x = f (g (h (x))) '. Questa è una convenzione molto vecchia (e vale anche per la sintassi di tipo C, quindi non è solo un Haskellism). È la sintassi del metodo punto che è "all'indietro", non l'operatore di composizione della funzione. Nota che nell'esempio di Scala il "flusso" è molto più difficile da tracciare; in realtà inizia nel mezzo a '(1 a 10)', quindi si sposta a destra, quindi torna improvvisamente a sinistra a 'println'. – Ben

risposta

16

Sfortunatamente, è il modo idiomatico di Haskell. Ma l'operatore & potrebbe fare quello che vuoi.

import Data.Function ((&)) 

[1..10] & filter (< 3) & map (**2) & show & putStrLn 

Sostanzialmente, (&) = flip ($). Allo stesso modo, Control.Arrow.(>>>) = flip (.)

UPDATE (6+ mesi dopo): Devo ammettere, questo problema è una grande fonte di frustrazione per me e mi sono state giocando con questo potenziale soluzione:

https://gist.github.com/obadz/9f322df8ba6c8a9767683d2f86af8589#file-directionalops-hs-L81

+2

Peccato che x & f >>> g' non riesca a causa della precedenza sbagliata ... corrisponderebbe strettamente a 'g. f $ x'. – chi

2

Perché non creare un nuovo operatore?

(#) :: a -> (a -> b) -> b 
(#) = flip id 

Ora si può semplicemente scrivere

[1..10] # filter (< 3) # map (**2) # show # putStrLn 

Questo è l'equivalente dell'operatore (&) da Data.Function.

5

Sì, è idiota Haskell. Non arabo, ma piuttosto matematico, derivato dalla sintassi per la composizione. Vedi anche Haskell composition (.) vs F#'s pipe forward operator (|>).

Eppure, anche in Haskell a volte preferisce scrivere le chiamate nella direzione opposta, e troverete un paio di librerie (per esempio Data.Function dal di base 4.8.0) che hanno definito

(&) = flip ($) 

in modo che puoi esprimere la tua chiamata come

[1..10] & filter (< 3) & map (**2) & show & putStrLn 
+0

L'unica volta in cui personalmente ho perso un operatore di concatenamento da sinistra a destra era ['fmap' in una monade] (http://stackoverflow.com/q/20203056/1048572) tuttavia – Bergi

Problemi correlati