【问题标题】:Creating my own State monad创建我自己的 State monad
【发布时间】:2014-03-30 10:02:46
【问题描述】:

我了解如何使用单子,但我并不真正掌握如何创建单子。所以我正在重新创建一个 State monad。

到目前为止,我已经创建了一个新类型 Toto(法语中的 foo)并将其作为 Monad 的一个实例。现在我正在尝试为其添加“阅读器功能”。我创建了一个 TotoReader 类,它声明了一个“get”函数。但是当我尝试实例化它时,一切都崩溃了。 GHC 告诉我它无法推断 (m ~ r)(底部的完整编译错误)。

但是当我创建一个顶级函数 get 时,一切正常。

那么我怎样才能在一个类中定义一个 get 函数,这真的是正确的做法吗?什么是我不明白的?

到目前为止我的代码如下

{-# OPTIONS -XMultiParamTypeClasses #-}
{-# OPTIONS -XFlexibleInstances #-}

newtype Toto s val = Toto { runToto :: s -> (val, s) }

toto :: (a -> (b,a)) -> Toto a b
toto = Toto

class (Monad m) => TotoReader m r where
    get :: m r

instance Monad (Toto a) where
    return a = toto $ \x -> (a,x)
    p >>= v  = toto $ \x ->
                    let (val,c) = runToto p x
                    in runToto (v val) c

instance TotoReader (Toto m) r where 
    get = toto $ \x -> (x, x) -- Error here

-- This is working
-- get :: Toto a b
-- get = toto $ \s -> (s,s)


pp :: Toto String String
pp = do 
    val <- get
    return $ "Bonjour de " ++ val

main :: IO ()
main = print $ runToto pp "France"

编译错误

test.hs:19:11:
    Could not deduce (m ~ r)
    from the context (Monad (Toto m))
      bound by the instance declaration at test.hs:18:10-30
      `m' is a rigid type variable bound by
          the instance declaration at test.hs:18:10
      `r' is a rigid type variable bound by
          the instance declaration at test.hs:18:10
    Expected type: Toto m r
      Actual type: Toto m m
    In the expression: toto $ \ x -> (x, x)
    In an equation for `get': get = toto $ \ x -> (x, x)
    In the instance declaration for `TotoReader (Toto m) r'

【问题讨论】:

  • 虽然完全正确,但我发现Monad 实例声明令人困惑,因为您使用Toto a 作为类型,其中a 是表示状态的类型变量,但是在实现中,您将a 绑定到monad value,并将xc 绑定到状态。如果您将s 用于类型变量,将ss' 用于状态绑定,则会减少混乱。

标签: haskell monads state-monad


【解决方案1】:

让我们使用 ghci 来检查种类:

*Main> :k Toto
Toto :: * -> * -> *

Toto 有两个类型参数:环境类型和返回类型。如果r 是环境,Toto r 将是 monad 类型构造函数。

*Main> :k TotoReader
TotoReader :: (* -> *) -> * -> Constraint

TotoReader 有两个类型参数:monad 类型构造函数和环境类型,在我们的例子中分别是 Toto rr

所以,实例声明应该是这样的:

instance TotoReader (Toto r) r where 
    get = toto $ \x -> (x, x)

【讨论】:

  • 谢谢,忘记了,名字不一样,类型不能一样。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-09-11
  • 2019-05-19
  • 1970-01-01
  • 2012-10-08
  • 2013-06-19
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多