类似于 (>>=) 的函数,但返回不同的 monad
(>>=)
的类型是
(>>=) :: Monad m => m a -> (a -> m b) -> m b
我想要一个具有以下类型的函数:
(Monad m, Monad n) => m a -> (a -> n b) -> n b
此函数可用于将不同的 monad 链接在一起。
当我尝试从命令行参数 -p 3000
获取 3000
时,我遇到了这个问题:
main = getArgs >>= (\args -> (elemIndex "-p" args) >>= (\id -> warpDebug (fromIntegral.read (args !! (id+1))) Ilm))
这显然不会编译,因为 getArgs
返回一个 IO [String]
,elemIndex
返回一个 Maybe Int
。可以使用上述类型的函数来优雅地解决这个问题。我的问题是:
- 这个函数已经定义了吗? (Hoogle 没有找到任何)
- 如果没有,可能是由于某种原因。那到底是什么原因呢?这被认为是一种不好的做法吗?我认为这是比使用 case 表达式更好的方法。
The type of (>>=)
is
(>>=) :: Monad m => m a -> (a -> m b) -> m b
I want a function that has the type:
(Monad m, Monad n) => m a -> (a -> n b) -> n b
This function could be used to chain different monads together.
I faced this problem when I was trying to get 3000
from the command-line arguments -p 3000
:
main = getArgs >>= (\args -> (elemIndex "-p" args) >>= (\id -> warpDebug (fromIntegral.read (args !! (id+1))) Ilm))
This clearly won't compile because getArgs
returns an IO [String]
and elemIndex
returns a Maybe Int
. A function of the above type could be used to elegantly solve this problem. My question is:
- Is this function already defined? (Hoogle does not find any)
- If there isn't, it's probably due to some reason. What is the reason then? Is this considered a bad practice? I think it's a better way than having to use a case expression.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
这样的函数不存在。事实上,如果你将
n
作为恒等单子,它就可以让你构造一个函数ma ->; a
,显然不能为所有 monad 定义它。要解决“组合”两个 monad 的一般问题,您可以查看 monad 转换器。
然而,在你的例子中使用 monad 转换器似乎有点过分了。您可以简单地定义一个函数
[String] ->也许 Args
(对于某些自定义类型Args
- 在示例中说Int
),它执行命令行参数处理,然后对结果进行模式匹配(或使用也许
)来自IO
单子。Such a function doesn't exist. In fact, if you take
n
to be the identity monad, it would allow you to construct a functionm a -> a
, which clearly cannot be defined for all monads.To address the general problem of "composing" two monads, you can look into monad transformers.
However, it seems overkill to use monad transformers in your example. You can simply define a function
[String] -> Maybe Args
(for some custom typeArgs
- sayInt
in the example) which does the command line argument processing, then pattern match on the result (or usemaybe
) from within theIO
monad.这个函数不存在,因为它对所有 monad 都没有意义。它基本上相当于一个 monad 解包函数
Monad m =>;妈-> a
——唯一的区别是你立即将它放入另一个 monad 中。之所以没有为所有 monad 定义这个函数,是因为它对于其中一些 monad 来说没有意义。例如,以
也许
为例:如果您没有什么都没有
,解压它的唯一方法就是抛出一个错误,并且运行时错误会被忽视。一个更极端的例子是 IO——使用可以“解压”IO 值的函数会导致奇怪且潜在的不确定行为。因此,一般来说你没有这样的功能。然而,许多特定的单子确实都具有这样的功能。 runST 就是一个很好的例子;这实际上是处理状态的安全方法。实际上,您确实对于
Maybe
和IO
都有这样的函数(fromJust
和unsafePerformIO
分别),但它们存在我上面概述的问题,您应该避免它们。那么,解决你的问题的方法就是看看你正在处理的任何 monad 是否存在这样的函数。如果有,检查任何潜在的陷阱——它是否会产生运行时错误或导致奇怪的行为?
就您而言,如果您绝对确定
Maybe
永远不会Nothing
,请使用fromJust
。但是,这通常不是一个好的做法,因此您应该坚持使用Maybe
中的值进行模式匹配。This function doesn't exist because it would not make sense for all monads. It is basically equivalent to a monad unpacking function
Monad m => m a -> a
--the only difference is that you immediately put it into another monad.The reason this function is not defined for all monads is because it does not make sense for some of them. For example, take
Maybe
: the only way to unpack it would be to throw an error if you haveNothing
, and runtime errors are looked down upon. A more extreme example would beIO
--using a function that could "unpack"IO
values would lead to weird and potentially nondeterministic behavior.Thus, you do not have such a function in general. However, a lot of specific monads do come with such functions. A great example is
runST
; this is actually a safe way for dealing with state. You actually do have such functions for bothMaybe
andIO
(fromJust
andunsafePerformIO
respectively), but they have the problems I outlined above and you should avoid them.The solution to your problem, then, is to see if there exists such a function for whichever monads you're dealing with. If there does, check any potential pitfalls--does it generate runtime errors or cause weird behavior?
In your case, if you are absolutely sure that the
Maybe
is neverNothing
, usefromJust
. However, this is not generally good practice, so you should just stick to pattern matching the value out of theMaybe
.答案取决于您是否需要一起或单独使用 Maybe 和 IO monad。
如果您需要一起使用它们 - 答案是您需要通过构建包含 IO monad 和 MaybeT monad 转换器的 monad 转换器堆栈来组合
IO
和Maybe
monad。如果您单独需要它们,则可以使用更简单的解决方案:
请注意
返回
。因此,在内层括号中(elemIndex
和900
之间)有Maybe
monad,但没有 IO。也就是说,在离开Maybe
monad 之前,您无法执行 IO 操作,正如我在 print 中展示的那样。The answer depends on whether you need to use Maybe and IO monads together or separately.
If you need to use them together - the answer is that you need to compose
IO
andMaybe
monads by constructing a stack of monad transformers containing IO monad and MaybeT monad transformer.If you need them separately, then a simpler solution works:
Note the
return
. So you haveMaybe
monad in the inner parentneses (betweenelemIndex
and900
), but not IO. That is, you cannot perform IO actions before leavingMaybe
monad, as I showed with print.