【问题标题】:Making Haskell Monads制作 Haskell Monad
【发布时间】:2018-03-15 00:15:22
【问题描述】:

我正在尝试在 Haskell 中创建一个非常简单的 monad。 monad 没有什么特别的,只是持有一个计数器作为状态。

module EmptyMonad
  ( EmptyMonad
  ) where

import Control.Monad

data EmptyMonad a = EmptyMonad
  { myValue :: a
  , myState :: Int
  } deriving (Show)

instance (Eq a) => Eq (EmptyMonad a) where
  EmptyMonad x1 y1 == EmptyMonad x2 y2 = x1 == x2 && y1 == y2


instance Monad (EmptyMonad a) where
  return x = EmptyMonad x 0
  (EmptyMonad x y) >>= f = EmptyMonad x (y + 1)

在 Monads 上花了几个小时后,我无法理解编译器的错误:

EmptyMonad.hs:16:10: error:
    • Expecting one fewer argument to ‘Monad EmptyMonad’
      Expected kind ‘k0 -> Constraint’,
        but ‘Monad EmptyMonad’ has kind ‘Constraint’
    • In the instance declaration for ‘Monad EmptyMonad a’
Failed, modules loaded: none.

【问题讨论】:

  • 你应该写instance Monad EmptyMonad where(没有a)。
  • 此外,它应该是(EmptyMonad x y) >>= f = EmptyMonad (f x) (y + 1)。 (与f),否则类型不匹配。
  • 除了理解和使用 Haskell 语法的问题之外,您还会遇到语义问题。在 monad 中计数绑定是不行的;它违反了“return 是一个身份”定律,即 return x >>= f = f x,因为等式右侧的绑定较少。 (不过,这似乎是每个人对新 monad 的第一个想法,包括我的!)
  • 参见this question,它也询问了“counter monad”。

标签: haskell monads


【解决方案1】:

这里有两个主要问题:

  • 实例声明确实期望一种种类* -> *。所以例如[]不是[a];和
  • 绑定运算符>>= 期望EmptyMonad a 和函数a -> EmptyMonad b 并返回EmptyMonad b 元素。

所以我们可以通过以下解决方案解决问题:

instance Monad EmptyMonad where  -- no a after EmptyMonad
  return x = EmptyMonad x 0
  (EmptyMonad x y) >>= f = fx {myState = y+1}
      where fx = f x

所以在这里我们指定instance Monad EmptyMonad,因为EmptyMonad 有一种* -> *。此外,绑定运算符将计算f x,然后将该实例的myState 更改为y+1

话虽如此,现在您需要将EmptyMonad 设为ApplicativeFunctor 的实例。

【讨论】:

  • 为什么我不能使用EmptyMonad fx (y+1) 而不是fx {myState = y+1}
  • @user1 因为fxEmptyMonad b,而不是b。所以EmptyMonad fx (y+1) 将是一个EmptyMonad (EmptyMonad b)——一个嵌套的单子值!
猜你喜欢
  • 2012-10-31
  • 1970-01-01
  • 2018-12-12
  • 1970-01-01
  • 2013-08-15
  • 2013-05-16
  • 2011-05-27
  • 1970-01-01
相关资源
最近更新 更多