如何
使以下列表 monad 声明可编译?
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’
这里有一些潜在的陷阱,其中大部分都在评论中介绍:
- 没有为
Monad
实例定义mzero
,如果您尝试指定一个实例,则会收到错误。mzero
将在MonadPlus
实例中定义(如果有)。 - 尝试为内置列表重新定义 monad 实例是行不通的。 如果你想使用它,你需要定义你自己的
List
类型。 - 在"现代"Haskell(从GHC 7.10开始)中,应用=> Monad提案的实现已经淘汰了许多旧的Monad教程,并使用户定义的Monad更难编写,因为您还需要定义
Functor
和Applicative
实例(详细的迁移说明)。
因此,下面是列表示例的翻译,以使用用户定义的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)