2011-10-20 9 views
7

jestem definiowania instancji monady następująco:Czy Haskell zawsze wie, "wróć", aby zadzwonić?

data Something = Something a 

instance Monad Something where 
    return a = Something a  --Wraps a in 'Something', correct? 
    m >>= f = do 
     var <- m 
     return $ f var   --I want this to pass var to f, then wrap the result 
            --back up in the 'Something' monad with the return I 
            --Just defined 

Pytania są ->

1: Czy istnieją jakieś rażące błędy/wyobrażeń z tym, co robię?

2: Czy Haskell wiedzieć, aby zadzwonić do zwrotu mam zdefiniowanego powyżej z m >>= f

3: Jeśli z jakiegoś powodu określić inną funkcję

f :: Something a -> Something b 
f x = do 
    var <- x 
    return $ doMagicTo x 

Will return połączeń powrót I zdefiniowanego w monady instancja i wrap x w Something?

Odpowiedz

15

Jest tu kilka dużych problemów.

Po pierwsze, instancja Monad musi mieć kind* -> *. Oznacza to, że potrzebna jest co najmniej jedna zmienna typu , w której Twój Something nie ma żadnych. Dla porównania:

-- kind * -> * 
Maybe 
IO 
Either String 

-- kind * 
Maybe Int 
IO() 
Either String Double 

Zobacz, jak każdy z Maybe, IO i Either String potrzebują parametr typu, zanim będzie można z nich korzystać? Z Something, nie ma miejsca dla parametru Typ wypełnić Więc trzeba zmienić definicję.

data Something a = Something a 

Drugim wielkim problemem jest to, że w przypadku >>= Monad jest źle. Zwykle nie można używać do-notacji, ponieważ to po prostu wywołuje funkcje Monad funkcji return i >>=. Musisz więc napisać to bez żadnych funkcji monady, albo do-notacji, albo wywołując >>= lub return.

instance Monad Something where 
    return a = Something a  --Wraps a in 'Something' 
    (Something m) >>= f = f m  --unwraps m and applies it to f 

Definicja >>= jest prostsza niż oczekiwano. Rozpakowanie m jest łatwe, ponieważ wystarczy dopasować do wzoru na konstruktorze Something. Również f :: a -> m b, więc nie musisz się martwić o jego zawijanie, ponieważ f robi to za ciebie.

Chociaż nie ma sposobu, aby rozpakować monady w ogólnym, bardzo wiele specyficzne monady można odwinąć.

Należy pamiętać, że nie ma nic niewłaściwego syntaktycznie w używaniu notacji-do-notacji lub >>= w deklaracji monad. Problem polega na tym, że >>= jest zdefiniowany rekursywnie, więc program próbuje przejść do niekończącej się pętli.

(nb Something zdefiniowany tutaj jest Identity monad)

Na swoim trzecim pytaniu, tak funkcja return zdefiniowane w instancji Monad to taka, która zostanie wywołana. Klasy typów są wywoływane według typu, a ponieważ określony typ musi być Something b, kompilator automatycznie użyje instancji Monad dla Something. (Myślę, że oznaczało to, że ostatnia linia to doMagicTo var).

+3

To jest świetne. Wszystkie te odpowiedzi są tak dobre. Czuję się zmuszony zauważyć, że społeczność Haskell była jak dotąd najbardziej pomocna i dokładna, z jakimi się zetknąłem. Na zdrowie. – providence

2
  1. Zamknij. return jest tu nadmiarowy i musisz dodać parametr typu do konstruktora typu Something. Edytuj: Ten kod jest nadal nieprawidłowy. Definicja >>= jest okrągła. Zobacz inne odpowiedzi, aby uzyskać więcej informacji.

    data Something a = Something a 
    
    instance Monad Something where 
        return a = Something a 
        m >>= f = do 
         var <- m 
         f var 
    
  2. Ponieważ definicja >>= jest pod instance Monad Something where typu >>= „s jest Something a -> (a -> Something b) -> Something b. Więc może powiedzieć, że f var musi być typu Something b. Terminem google tutaj jest "typ wnioskowania"

  3. Tak. Ponownie, jest to wnioskowanie typu. Jeśli kompilator nie może wywnioskować, jaki typ chcesz, powie ci to. Ale zwykle może.

+0

Zobacz rozwiązanie Johna L: nie możesz użyć bloku do-do, aby zdefiniować '>> = tak, ponieważ jak myślisz, w jaki sposób blokada zostaje usunięta? (Podano także w rozwiązaniu z rampy). – ivanm

+0

D'oh, dobry telefon. Muszę teraz myśleć bardziej jak programista Haskella, odkąd po prostu wziąłem kod OP, zmodyfikowałem go, aż został sprawdzony i skompilowany, i powiedział: "Tak, to musi być słuszne". : P Wciąż myślę, że pytanie PO było mniej więcej "Czy Haskell dokonuje wnioskowania?" chociaż nie pytali w ten sposób. I moim głównym punktem było, tak, to prawda. – MatrixFrog

7

Głównym problemem jest to, że Twoja definicja >>= jest okrągła.

Haskell'a zrobić składnia jest cukier syntatic dla łańcuchów >>= i >>, więc definicji

m >>= f = do 
    var <- m 
    return $ f var   

Desugars do

m >>= f = 
    m >>= \var -> 
    return $ f var 

Więc definiowania m >>= f jako m >>= \..., która jest okrągła.

To, co należy zrobić z >>=, to zdefiniować, jak wyodrębnić wartość z m, aby przejść do f. Ponadto Twój f powinien zwrócić monadyczną wartość, więc użycie return jest tutaj niepoprawne (jest bliżej definicji fmap).

Definicja >>= dla Something mogą być:

(Something a) >>= f = f a 

To Identity Monada - jest sporo pisano o nim - to dobry punkt wyjścia dla zrozumienia jak monady.

Powiązane problemy