haskell - TeletypeIO 的 StateMonad 实例
问题描述
所以,我有这个数据类型(它来自这里:https ://wiki.haskell.org/IO_Semantics ):
data IO a = Done a
| PutChar Char (IO a)
| GetChar (Char -> IO a)
我想为它写一个 StateMonad 实例。我已经为它编写了 Monad 和 Applicative 实例。
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)’
解决方案
正如我在评论中提到的,您的类型实际上并不持有任何状态,因此StateMonad
实例对它来说是荒谬的。
但是,由于这只是一个练习(也基于评论),我想从技术上实现该实例是可以的,即使它没有按照您的预期执行。
首先,你得到的编译器错误告诉你这个MonadState
类实际上有两个参数——状态的类型和 monad 的类型,其中 monad 必须有 kind * -> *
,也就是说,有一个类型参数,likeMaybe
或 list , 或Identity
.
在您的情况下,有问题的单子(不是真正的单子,但可以)是IO
,并且您的“状态”的类型是Char
,因为这就是您要注意get
的put
。所以声明必须如下所示:
instance MonadState Char IO where
其次,该state
方法没有(s -> s) -> m s
您声称的签名,而是(s -> (a, s)) -> m a
. 见其定义。它应该做的是用一个函数在 monad 中创建一个计算m
,该函数接受一个状态并返回“结果”加上新的(更新的)状态。
另请注意,这是对 State monad 最一般的操作,两者get
和put
都可以表示为state
:
get = state $ \s -> (s, s)
put s = state $ \_ -> ((), s)
get
这意味着您不必put
自己实施。您只需要实现该state
功能,并且get
/put
将来自默认实现。
顺便说一句,这也适用于另一种方式:如果您定义get
and put
,则定义 ofstate
将来自默认值:
state f = do
s <- get
let (a, s') = f s
put s'
return a
现在,让我们看看这实际上是如何实现的。
's 参数的语义state
是这样的:它是一个函数,它以某个状态为输入,然后根据该状态进行一些计算,这个计算有一些结果a
,它也可能以某种方式修改状态;所以函数返回结果和新的修改状态。
在您的情况下,从“monad”“获取”状态GetChar
的方式是 via ,而“返回”的Char
方式是通过调用您传递给它的函数(这种函数通常称为“延续”)。
将状态“放入”回“monad”的方法是 via PutChar
,它将Char
您想要“放入”的参数作为参数,加上一些IO a
代表计算“结果”的参数。
因此,实现的方法state
是(1)首先“获取” Char
,然后(2)将函数应用于它,然后(3)“放置”结果 new Char
,然后(3)返回“结果”功能。把它们放在一起:
state f = GetChar $ \c -> let (a, c') = f c in PutChar c' (Done 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...>
推荐阅读
- python - python pact verifier 没有从代理中检索协议
- javascript - 链接到最后一个滚动位置而不是锚点
- python - 如何在for循环输出中删除excel的标题行
- django - wagtail 如何 JSON 序列化 ListBlock 中的 RichText 字段
- drupal-8 - 是否可以在 Drupal 8 控制器中返回多个模板
- jenkins - 将 ActiveChoices 脚本导入多个 Jenkinsfile
- python - 如何在python树视图中插入字典值
- maven - 无法将工件 org.apache.maven.shared:file-management:pom:3.0.0 从/传输到中央(https://repo.maven.apache.org/maven2)
- php - 如何通过 exec() 将参数从 PHP 传递给 R 脚本并在 R 脚本中使用?
- postgresql - POSTGRESQL:在 'date_to' 列和 'date_from' 列之间生成它们已经存在于 postgresql 中的系列