2013-06-06 18 views
8

Próbuję wygaśnięcia oświadczenia do wykonania w Haskell. Znalazłem kilka przykładów tutaj na SO, ale nie był w stanie zastosować je do mojej sprawy. Jedyne, co mogę wymyślić, to ciężkie zagnieżdżone oświadczenie, które wydaje się dość brzydkie.Haskell do notacji do wiązania

komunikat, w którym zrobić zapis powinien zostać zastąpiony wiąże:

do num <- numberNode x 
    nt1 <- numberTree t1 
    nt2 <- numberTree t2 
    return (Node num nt1 nt2) 

Wszelkie dane wejściowe jest wysoko ceniona =)

Odpowiedz

11
numberNode x >>= \num -> 
    numberTree t1 >>= \nt1 -> 
    numberTree t2 >>= \nt2 -> 
     return (Node num nt1 nt2) 

Zauważ, że to jest prostsze, jeśli używasz Applicatives:

Node <$> numberNode x <*> numberTree t1 <*> numberTree t2 
+0

Dziękuję za wciśnięcie mojej głowy o tę ścianę. Nie wiem dlaczego, ale po prostu nie miałem prostego rozwiązania. – floAr

+0

Nie ma za co! –

7

Jest to doskonały przypadek użycia dla applicative style. Można wymienić cały fragment (po imporcie Control.Applicative) z

Node <$> numberNode x <*> numberTree t1 <*> numberTree t2 

myśleć o stylu aplikacyjnej (używając <$> i <*>) jako „Podnoszenie” aplikacji funkcji tak to działa na funktorów również. Jeśli mentalnie zignorujesz <$> i <*>, wygląda to całkiem podobnie do zwykłej aplikacji!

Styl aplikacyjny jest przydatny, gdy masz czystą funkcję i chcesz nadać jej nieczyste argumenty (lub jakiekolwiek argumenty funktora) - w zasadzie, gdy chcesz zrobić to, co określono w pytaniu!


typu podpis <$> jest

(<$>) :: Functor f => (a -> b) -> f a -> f b 

co oznacza, że ​​ma czystej funkcji (w tym przypadku Node) i wartość funktora (w tym przypadku numberNode x) i tworzy nową funkcję owinięty "wewnątrz" funktora. Możesz dodać kolejne argumenty do tej funkcji z <*>, który ma podpis typu

(<*>) :: Applicative f => f (a -> b) -> f a -> f b 

Jak widać, jest to bardzo podobne do <$> tylko to działa nawet wtedy, gdy funkcja jest owinięty „wewnątrz” funktorem.

+0

Dziękuję za wzmiankę o tym, nie mam żadnego doświadczenia z aplikacjami, ale koncepcja wygląda niesamowicie. To jest właśnie ten rodzaj pięknych sposobów na rozwiązywanie problemów, które lubię w Haskellu :) Ponieważ pytałem o operatora binda, przyjmuję odpowiedź Gabrielsa, ale na pewno przyjrzę się głębiej tej koncepcji. Bardzo dziękuję za wskazanie tego mnie =) – floAr

2

Chciałbym dodać do słupków około aplikacyjnych powyższych ..

Biorąc pod uwagę rodzaj <$>:

(<$>) :: Functor f => (a -> b) -> f a -> f b 

wygląda jak FMapy:

fmap :: Functor f => (a -> b) -> f a -> f b 

który jest również bardzo podobne do Control.Monad.liftM:

liftM :: Monad m => (a -> b) -> m a -> m b 

myślę o tym, jak „muszę podnieść konstruktora danych w tego typu”

Na powiązana uwaga, jeśli znajdziesz się w ten sposób:

action >>= return . f 

cię zamiast tego może to zrobić:

f `fmap` action 

Pierwszy przykład to użycie binda do pobrania wartości z działania dowolnego typu to jest wywołanie f, a następnie przepakowanie wyniku. Zamiast tego możemy podnieść f, aby przyjąć argumenty za rodzaj działania.

+0

Dzięki za wyjaśnienie ciągłe =) – floAr

+1

'liftM3 :: Monad m => (a1 -> a2 -> a3 -> r) -> m a1 -> m a2 - > m a3 -> mr' lub 'liftA3 :: Applicative f => (a -> b -> c -> d) -> fa -> fb -> fc -> fd' są dostępne poprzez zaimportowanie' Control.Monad' lub 'Control.Applicative' i są bardziej użyteczne niż zwykłe' fmap'/'liftM' tutaj. Na przykład, węzeł liftA3 (numberNode x) (numberTree t1) (numberTree t2) 'zrobiłoby lewę. – AndrewC

+0

W obecnej wersji nie odpowiada to na pytanie. OP nie może go użyć do rozwiązania problemu, który mają. Dlatego potrzebujesz liftM3 lub Applicative. – AndrewC