如何结合两个不同的monad [英] How to combine two different monads

查看:169
本文介绍了如何结合两个不同的monad的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在测试一台REST服务器。我在IO monad中找到它,并在 State Db 中模拟它,其中 Db 跟踪服务器的假定状态。下面的函数应该运行两个版本并比较结果...

  check ::(Eq a,MonadState ds) => s a  - > IO a  - > s(IO Bool)
- 或者:check ::(等式a,MonadState d s,MonadIO i)=> s a - >我 - - > s(i Bool)
check _ _ =(return.return)False - 现在



<但是当我尝试使用这些最简单的功能时...

  simReset :: State Db()
realReset :: IO()

reset :: StateT Db IO Bool
reset = check simReset realReset

我得到这个错误:

 无法匹配预期类型`Bool'与实际类型`IO Bool'
预期类型:StateT Db IO Bool
实际类型:StateT Db IO(IO Bool)
在'check'调用的返回类型中
在表达式:检查simReset realReset

为什么?我该如何解决它?



(本主题从这里开始:提升以修复单元变压器堆栈的*内部*)

解决方案在你的实现中, check 会返回一个 IO Bool ,而不管状态monad s 是。因此,当您传递 simReset 来检查状态Db monad中的一次性操作时,返回值为将会是 State Db(IO Bool)



如何解决这个问题取决于你想要做什么做。基于你对 reset 的实现,你似乎试图与一个形式为 StateT Db IO a 。在这种情况下,您在 StateT Db IO 的上下文中描述了一种程序。有两种方法可以解决这个问题:


  1. 您可以升级 simReset 键入 MonadState Db s => s()(这实际上不需要任何实施变更)。

  2. 您可以定义一个提升它进入正确的monad


例如:

  hoistState :: Monad m =>国家a  - > StateT s m a 
hoistState prg = StateT $ \st - >返回$ runState prg st

在任何情况下,您都可能想要保留重新执行并且结果在相同monad中:

  check ::(等式a,MonadIO s,MonadState ds)=> s a  - > IO a  - > s Bool 

然后,在解决方案一中,您有

  reset = check simReset realReset 

你有两个:

$ p $ reset = check(hoistState simReset)realReset


I'm testing a REST server. I hit it in the IO monad and simulate it in State Db where Db tracks the supposed state of the server. The following function is supposed to run both versions and compare the results...

check :: (Eq a, MonadState d s) => s a -> IO a -> s (IO Bool)
-- or: check :: (Eq a, MonadState d s, MonadIO i) => s a -> i a -> s (i Bool)
check _ _ = (return.return) False -- for now

but when I try it with these simplest possible functions ...

simReset :: State Db ()
realReset :: IO ()

reset :: StateT Db IO Bool
reset = check simReset realReset

I get this error:

Couldn't match expected type `Bool' with actual type `IO Bool'
Expected type: StateT Db IO Bool
  Actual type: StateT Db IO (IO Bool)
In the return type of a call of `check'
In the expression: check simReset realReset

Why? And how do I fix it?

(This topic started here: Lift to fix the *inside* of a monad transformer stack)

解决方案

In your implementation, check is going to return an IO Bool regardless of what the state monad s is. So, when you pass simReset to check, which is a monadic action in the State Db monad, the return value is going to be State Db (IO Bool).

How to fix it depends on what you're trying to do. Based on your implementation of reset it seems like you're trying to interface with a transformer stack of the form StateT Db IO a. In this case, you're describing a kind of program in the context of StateT Db IO. There are two ways to go about this:

  1. You can upgrade simReset to have type MonadState Db s => s () (This shouldn't actually require any implementation change).

  2. You can define an auxiliary function that "hoists" it into the proper monad

For example:

hoistState :: Monad m => State s a -> StateT s m a
hoistState prg = StateT $ \st -> return $ runState prg st

In either case, you'll probably want to keep the action that you're performing and the result in the same monad:

check :: (Eq a, MonadIO s, MonadState d s) => s a -> IO a -> s Bool

Then, with solution one, you have

reset = check simReset realReset

And with solution two you have:

reset = check (hoistState simReset) realReset      

这篇关于如何结合两个不同的monad的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆