类似于 (>>=) 的函数,但返回不同的 monad

发布于 2024-12-22 17:48:02 字数 874 浏览 4 评论 0原文

(>>=) 的类型是

(>>=) :: 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

无敌元气妹 2024-12-29 17:48:02

这样的函数不存在。事实上,如果你将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 function m 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 type Args - say Int in the example) which does the command line argument processing, then pattern match on the result (or use maybe) from within the IO monad.

迷爱 2024-12-29 17:48:02

这个函数不存在,因为它对所有 monad 都没有意义。它基本上相当于一个 monad 解包函数 Monad m =>;妈-> a——唯一的区别是你立即将它放入另一个 monad 中。

之所以没有为所有 monad 定义这个函数,是因为它对于其中一些 monad 来说没有意义。例如,以也许为例:如果您没有什么都没有,解压它的唯一方法就是抛出一个错误,并且运行时错误会被忽视。一个更极端的例子是 IO——使用可以“解压”IO 值的函数会导致奇怪且潜在的不确定行为。

因此,一般来说你没有这样的功能。然而,许多特定的单子确实都具有这样的功能。 runST 就是一个很好的例子;这实际上是处理状态的安全方法。实际上,您确实对于MaybeIO都有这样的函数(fromJustunsafePerformIO分别),但它们存在我上面概述的问题,您应该避免它们。

那么,解决你的问题的方法就是看看你正在处理的任何 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 have Nothing, and runtime errors are looked down upon. A more extreme example would be IO--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 both Maybe and IO (fromJust and unsafePerformIO 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 never Nothing, use fromJust. However, this is not generally good practice, so you should just stick to pattern matching the value out of the Maybe.

苏辞 2024-12-29 17:48:02

答案取决于您是否需要一起或单独使用 Maybe 和 IO monad。

如果您需要一起使用它们 - 答案是您需要通过构建包含 IO monad 和 MaybeT monad 转换器的 monad 转换器堆栈来组合 IOMaybe monad。

如果您单独需要它们,则可以使用更简单的解决方案:

import System.Environment
import Data.List

main = getArgs >>= (\args -> return (elemIndex "-p" args 
    >>= \y -> return $ y + 900) >>= print)

请注意返回。因此,在内层括号中(elemIndex900 之间)有 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 and Maybe 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:

import System.Environment
import Data.List

main = getArgs >>= (\args -> return (elemIndex "-p" args 
    >>= \y -> return $ y + 900) >>= print)

Note the return. So you have Maybe monad in the inner parentneses (between elemIndex and 900), but not IO. That is, you cannot perform IO actions before leaving Maybe monad, as I showed with print.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文