2015-11-08 13 views
9

Pochodzę ze Scala. Więc często robić rzeczy jak:Metody łączenia od lewej do prawej w Haskell (w przeciwieństwie do prawej do lewej)

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

W Haskell, po odkryłem mogę pozbyć się wszystkich zagnieżdżonych nawiasów stosując $ i ., niedawno znalazłem się pisząc:

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

Teraz, to działa, ale kod czyta od prawej do lewej i jeśli nie przejdę na język arabski, trudno mi o tym mówić.

Czy jest jakaś inna sztuczka, która sprawia, że ​​łączę funkcje od lewej do prawej? Czy to tylko idiomatyczny sposób Haskella?

+1

Zauważ, że 'putStrLn. show = print'. Możesz również użyć 'mapM' lub' forM': 'forM [x | x <- [1..10], x <3] $ print. (** 2) 'lub coś podobnego. – Bakuriu

+0

Gdy już się do tego przyzwyczaisz, od lewej do prawej łatwiej się zastanowić: podaje typ wyrażenia. W twoim przypadku 'putStrnLn ...' Wiem, że to IO. – mb14

+1

Nieprzydatna obserwacja: "przepływ" zwykłego zastosowania funkcji łańcuchowej (bez użycia składu funkcji) jest od prawej do lewej: 'f. g. h $ x = f (g (h (x))) '. Jest to bardzo stara konwencja (i zawiera nawet składnię podobną do C, więc to nie jest tylko Haskelizm). Jest to składnia metodą kropkową, która jest "wsteczna", a nie operator składu funkcji. Zauważ, że w twoim przykładzie Scala "przepływ" jest trudniejszy do prześledzenia; faktycznie zaczyna się w środku na '(1 do 10)', następnie przesuwa się w prawo, a następnie nagle przeskakuje z powrotem na lewo do 'println'. – Ben

Odpowiedz

16

Niestety, jest to sposób idiomatyczny Haskella. Ale operator & może robić, co chcesz.

import Data.Function ((&)) 

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

Zasadniczo, (&) = flip ($). Podobnie Control.Arrow.(>>>) = flip (.)

Update (6+ miesięcy później): Muszę przyznać, że ta kwestia jest wielkim źródłem frustracji dla mnie i I zostały toying z tym potencjalne rozwiązanie:

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

+2

Szkoda, że ​​'x & f >>> g' nie działa z powodu niewłaściwego pierwszeństwa ... ściśle pasuje do' g. f $ x'. – chi

2

Dlaczego nie założyć nowego operatora?

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

Teraz można po prostu napisać

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

ten jest odpowiednikiem operatora (&) z Data.Function.

5

Tak, to idiotyczny Haskell. Nie arabski, ale raczej matematyczny, wywodzący się ze składni kompozycji. Zobacz także Haskell composition (.) vs F#'s pipe forward operator (|>).

Mimo to, nawet w Haskell czasami wolą pisać swoje rozmowy w innym kierunku, a znajdziesz kilka bibliotek (np Data.Function ponieważ baza 4.8.0), które zostały zdefiniowane

(&) = flip ($) 

tak że możesz wyrazić swoje połączenie jako

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

Jedynym momentem, w którym osobiście opuściłem operator łączenia łańcuchów od lewej do prawej, było ['fmap' w monadzie] (http://stackoverflow.com/q/20203056/1048572) – Bergi

Powiązane problemy