2017-01-08 12 views
0

Как сделать следующее объявление списка монады?Правильное определение класса монады

module Main where 

instance Monad m where 
    -- "return" constructs a one-item list. 
    return x = [x] 
    -- "bind" concatenates the lists obtained by applying f to each item in list xs. 
    xs >>= f = concat (map f xs) 
    -- The zero object is an empty list. 
    mzero = [] 

В настоящее время я получаю следующее сообщение об ошибке:

monad_ex1.hs:9:3: ‘mzero’ is not a (visible) method of class ‘Monad’ 

Мой код из https://en.wikipedia.org/wiki/Monad_(functional_programming)#Collections, цель состоит в том, чтобы запустить создать компилируемый код этого, импортировать его в GHCI и поиграйте с ним.

Удаление mzero из кода приводит к другому зашифрованному сообщению:

Illegal instance declaration for ‘Monad m’ 
     (All instance types must be of the form (T a1 ... an) 
     where a1 ... an are *distinct type variables*, 
     and each type variable appears at most once in the instance head. 
     Use FlexibleInstances if you want to disable this.) 
    In the instance declaration for ‘Monad m’ 
+0

Как говорится в ошибке, монады не имеют «нулевого объекта» или «mzero». – melpomene

+2

'instance Monad m' сделает все возможные типы' m' экземпляром 'Monad'. Вам понадобится «экземпляр Monad []', но это уже существует в стандартной библиотеке. Вы должны определить свой собственный класс или свой собственный тип, чтобы иметь возможность предоставить такой экземпляр. – melpomene

+0

Мне непонятно, почему вы добавили это «mzero» при определении экземпляра для класса типа monad. – BarbedWire

ответ

3

Есть несколько потенциальных ловушек здесь, большинство из которых покрыты в комментариях:

  • Там нет mzero определен для экземпляров Monad, и вы получите сообщение об ошибке, если попытаетесь указать его. mzero будет определен в экземпляре MonadPlus, если таковой имеется.
  • Попытка переопределить экземпляр монады для встроенных списков не будет работать. Вам нужно определить свой собственный тип List, если вы хотите поиграть с этим.
  • В «современном» Haskell (с GHC 7.10), реализация Applicative => Monad Proposal имеет устарела много старых учебники Monad и сделала определенный пользователь Монады немного больше трудно писать, потому что вы также должны определить Functor и Applicative экземпляров (detailed migration instructions).

Итак, приведен пример вашего примера с использованием пользовательского типа List с совместимым с GHC 7.10 шаблоном. Обратите внимание, что определение для return вместо этого перемещается в Applicative экземпляр pure.

module MyListMonad where 

import Control.Monad 

data List a = Empty | Cons a (List a) deriving (Show, Eq) 

instance Functor List where 
    fmap = liftM      -- boilerplate 
instance Applicative List where 
    pure x = Cons x Empty    -- put definition of `return` here 
    (<*>) = ap 
instance Monad List where 
    return = pure      -- boilerplate 
    (>>) = (*>)      -- boilerplate 
    xs >>= f = myConcat (myMap f xs) -- bind definition here 

myConcat :: List (List a) -> List a 
myConcat (Cons lst rest) = myAppend lst (myConcat rest) 
myConcat Empty = Empty 

myAppend :: List a -> List a -> List a 
myAppend (Cons x rest) ys = Cons x (myAppend rest ys) 
myAppend Empty ys = ys 

myMap :: (a -> b) -> List a -> List b 
myMap f (Cons x rest) = Cons (f x) (myMap f rest) 
myMap _ Empty = Empty 

test = do x <- Cons 1 $ Cons 2 $ Cons 3 Empty 
      y <- Cons 4 $ Cons 5 $ Empty 
      return (x * y)