正确定义 monad 类


如何

使以下列表 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更难编写,因为您还需要定义FunctorApplicative实例(详细的迁移说明)。

因此,下面是列表示例的翻译,以使用用户定义的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)

最新更新