Haskell TeletypeIO的StateMonad实例

Haskell TeletypeIO的StateMonad实例,haskell,io,monads,semantics,state-monad,Haskell,Io,Monads,Semantics,State Monad,所以,我有这个数据类型(它来自这里:): 我想为它写一个国家实例。我已经为它编写了Monad和应用程序实例 instance MonadState (IO s) where get = GetChar (\c -> Done c) put = PutChar c (Done ()) state f = Done (f s) 我不认为我完全理解在这里应该执行什么状态(以前称为“修改”) state :: (s -> (a, s)) -> m a 我还搞

所以,我有这个数据类型(它来自这里:):

我想为它写一个国家实例。我已经为它编写了Monad和应用程序实例

instance MonadState (IO s) where
  get    = GetChar (\c -> Done c)
  put    = PutChar c (Done ())
  state f = Done (f s)
我不认为我完全理解在这里应该执行什么状态(以前称为“修改”)

state :: (s -> (a, s)) -> m a
我还搞砸了申报。我真的不明白出了什么问题,更不用说如何解决了。谢谢你的帮助

Expecting one more argument to ‘MonadState (IO s)’
Expected a constraint,
but ‘MonadState (IO s)’ has kind ‘(* -> *) -> Constraint’
In the instance declaration for ‘MonadState (IO s)’

MonadState
接受两个参数,顺序如下:

  • 国家的类型

  • 单子

  • 在这种情况下,monad是
    IO

    instance MonadState _ IO where
      ...
    

    您需要弄清楚是什么代替了下划线,正如我在注释中提到的,您的类型实际上不包含任何状态,因此对它来说,
    StateMonad
    实例是毫无意义的

    然而,由于这只是一个练习(也基于注释),我想从技术上实现该实例是可以的,即使它没有达到您期望的效果

    首先,您遇到的编译器错误告诉您,
    MonadState
    类实际上包含两个参数——状态类型和monad类型,其中monad必须具有kind
    *->*
    ,也就是说,具有一个类型参数,比如
    可能
    ,或者list,或者
    标识

    在您的例子中,所讨论的monad(不是真正的monad,但ok)是
    IO
    ,而您的“状态”类型是
    Char
    ,因为这就是您的
    get
    ting和
    put
    ting。因此,声明必须如下所示:

    instance MonadState Char IO where
    
    其次,state方法没有您声称的签名
    (s->s)->ms
    ,而是
    (s->(a,s))->ma
    。看见它应该做的是在monad
    m
    中创建一个计算,该计算来自一个函数,该函数获取一个状态并返回“result”加上新的(更新的)状态

    还要注意的是,这是状态monad上最通用的操作,
    get
    put
    都可以用
    State
    表示:

    get = state $ \s -> (s, s)
    put s = state $ \_ -> ((), s)
    
    这意味着您不必自己实现
    get
    put
    。您只需要实现
    state
    函数,而
    get
    /
    put
    将来自默认实现

    顺便说一句,这也是另一种方式:如果定义
    get
    put
    ,则
    状态的定义将来自默认值:

    state f = do
        s <- get
        let (a, s') = f s
        put s'
        return a
    
    作为进一步的练习,我鼓励您看看
    get
    put
    将如何展开,从我上面给出的定义开始,逐步进行替换。在这里,我将为您介绍几个第一步:

    get = state $ \s -> (s, s)
        -- Substituting definition of `state`
        = GetChar $ \c -> let (a, c') = (\s -> (s, s)) c in PutChar c' (Done a)
        -- Substituting (\s -> (s, s)) c == (c, c)
        = GetChar $ \c -> let (a, c') = (c, c) in PutChar c' (Done a)
        = <and so on...>
    
    get=state$\s->(s,s)
    --替换`国家'的定义`
    =GetChar$\c->let(a,c')=(\s->(s,s))c在PutChar c'(完成a)中
    --替换(\s->(s,s))c==(c,c)
    =GetChar$\c->let(a,c')=(c,c)在PutChar c'(完成a)中
    = 
    
    您的类型不包含任何类型的状态,因此对于它来说,
    MonadState
    实例是毫无意义的。您试图解决的问题是什么?@FyodorSoikin任务是:“为Teletype/IO定义MonadState实例”。之后还有一个问题“这个实例的行为与通常的状态类型有何不同?”,可能就是这样。哦,这是家庭作业吗?@FyodorSoikin不是真的,我只是在学习Haskell,这是我发现的任务之一。这有关系吗?我理解为什么
    get
    put
    是这样的(使用
    state
    ),我只是不理解为什么Haskell已经知道
    state
    应该如何工作,没有定义。Haskell不知道。这是在库中定义的<代码>获取
    /
    放置
    通过
    状态
    定义,
    状态
    通过
    获取
    /
    放置
    定义。无论您选择实现哪一部分,另一部分都将免费提供。
    state f = GetChar $ \c -> let (a, c') = f c in PutChar c' (Done a)
    
    get = state $ \s -> (s, s)
        -- Substituting definition of `state`
        = GetChar $ \c -> let (a, c') = (\s -> (s, s)) c in PutChar c' (Done a)
        -- Substituting (\s -> (s, s)) c == (c, c)
        = GetChar $ \c -> let (a, c') = (c, c) in PutChar c' (Done a)
        = <and so on...>