2015-09-01 13 views
7

W poniższym instancji Monady:kłopoty ze zrozumieniem Monada (->)

instance Monad ((->) r) where 
    return = const 
    f >>= k = \ r -> k (f r) r 

Jest to zmusza k będzie funkcją dwóch parametrów? A jeśli tak, to dlaczego chcesz przekazać (f r) i r do k?

+0

Może Ci się spodobać sekcja [Monads as Containers] (https://wiki.haskell.org/Monads_as_containers) na monadzie czytelnika (poszukaj "czytnika"). –

+0

Tak 'k' jest funkcją' a -> r -> b'. 'r' jest jedyną instancją' r', którą masz i 'f r' jest jedynym sposobem na uzyskanie' a', więc nie masz dużego wyboru. – Lee

+0

możliwy duplikat [sposobu użycia (->) przypadków Monady i zamieszania związanego z (->)] (http://stackoverflow.com/questions/5310203/how-to-use-ventions-monases-and- zamieszanie-o) – Cactus

Odpowiedz

9

Czy to wymuszenie k jest funkcją dwóch parametrów?

Tak. Patrząc na definicję Monad mamy

class Monad m where 
    return :: a -> m a 
    (>>=) :: m a -> (a -> m b) -> m b 

Podstawiając (->) r dla m mamy

return :: a -> (->) r a 
(>>=) :: (->) r a -> (a -> (->) r b) -> (->) r b 

Teraz (->) r a jest po prostu dziwne Składnia r -> a i podobnie dla innych przypadków, więc dostać

return :: a -> r -> a 
(>>=) :: (r -> a) -> (a -> r -> b) -> r -> b 

widzimy więc, że rzeczywiście drugi argument do >>= musi być funkcją (przynajmniej) dwóch argumentów.

Dlaczego? Ponieważ funkcja dwóch argumentów jest po prostu funkcją przyjmującą jeden argument i zwracającą funkcję jednego argumentu, podczas gdy drugi argument do >>= powinien być funkcją przyjmującą jeden argument i zwracającą wartość konstruktora typu monady; dla funkcji monad ta wartość będzie funkcją. Stąd drugi argument do >>= będzie funkcją dwóch argumentów.

[W] hy chciałbyś przekazać (f r) I r do k?

Po części dlatego, że typ (->) r pasuje do jednolitej struktury Monady, co jest przydatne z wielu powodów.

Częściowo k nie wie, której funkcji używa f. Oznacza to, że z perspektywy k oba argumenty są naprawdę niezależne --- k nie mogą obliczyć jednego z drugiego.

Rozważmy tę funkcję:

-- | 'f' takes two numbers and adds them together 
f :: (->) (Int, Int) Int 
f = fst >>= \ n0 -> snd >>= \ n1 -> return (n0 + n1) 

Funkcja \ n0 -> snd >>= \ n1 -> return (n0 + n1) nie obchodzi gdzie jej argument pochodzi, lub w szczególności, że jej argument jest pierwszym elementem na wejściu. Więc potrzebuje zarówno argumentu n0, jak i pełnego wejścia.

Powiązane problemy