正确定义 monad class
Properly defining a monad class
如何使列表 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
类型。
- 在"modern"Haskell(从GHC 7.10开始),执行Applicative => Monad Proposal has obsoleted a lot of old Monad tutorials and made user-defined Monads a little more difficult to write because you also need to define
Functor
and Applicative
instances (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)
如何使列表 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
类型。 - 在"modern"Haskell(从GHC 7.10开始),执行Applicative => Monad Proposal has obsoleted a lot of old Monad tutorials and made user-defined Monads a little more difficult to write because you also need to define
Functor
andApplicative
instances (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)