Haskell 类似于(>;=)但返回不同单子的函数
Haskell 类似于(>;=)但返回不同单子的函数,haskell,monads,Haskell,Monads,(>>=)的类型为 (>>=) :: Monad m => m a -> (a -> m b) -> m b 我想要一个具有以下类型的函数: (Monad m, Monad n) => m a -> (a -> n b) -> n b 此函数可用于将不同的单子链接在一起 当我试图从命令行参数-p3000获取3000时,我遇到了这个问题: main = getArgs >>= (\args -> (elemIndex
(>>=)
的类型为
(>>=) :: Monad m => m a -> (a -> m b) -> m b
我想要一个具有以下类型的函数:
(Monad m, Monad n) => m a -> (a -> n b) -> n b
此函数可用于将不同的单子链接在一起
当我试图从命令行参数-p3000
获取3000
时,我遇到了这个问题:
main = getArgs >>= (\args -> (elemIndex "-p" args) >>= (\id -> warpDebug (fromIntegral.read (args !! (id+1))) Ilm))
这显然无法编译,因为getArgs
返回一个IO[String]
,而elemIndex
返回一个Maybe Int
。上述类型的函数可用于优雅地解决此问题。我的问题是:
- 这个函数已经定义了吗?(找不到任何)
- 如果没有,可能是因为某种原因。那么原因是什么呢?这被认为是一种不好的做法吗?我认为这是一种比使用大小写更好的方式
- 这样的功能不存在。事实上,如果您将
n
作为标识单子,它将允许您构造一个函数ma->a
,这显然不能为所有单子定义
为了解决“组合”两个单子的一般问题,您可以研究
然而,在您的示例中使用monad转换器似乎有些过分。您可以简单地定义一个函数
[String]->可能是Args
(对于示例中的某些自定义类型Args
-比如Int
),该函数执行命令行参数处理,然后对结果进行模式匹配(或使用)从IO
monad.这个函数不存在,因为它对所有monad都没有意义。它基本上相当于一个monad解包函数monad m=>ma->a
——唯一的区别是您可以立即将它放入另一个monad中
之所以没有为所有单子定义此函数,是因为它对其中一些单子没有意义。例如,以Maybe
为例:解包的唯一方法是在没有的情况下抛出一个错误,并且运行时错误被忽略。一个更极端的例子是IO
——使用一个可以“解包”IO
值的函数会导致奇怪的、潜在的不确定性行为
因此,您通常没有这样的功能。然而,很多特定的单子都有这样的函数。一个很好的例子是runST
;这实际上是一种处理国家问题的安全方法。实际上,对于可能
和IO
(分别是fromJust
和unsafePerformIO
),您确实有这样的函数,但它们存在我上面概述的问题,您应该避免它们
那么,你的问题的解决办法就是看看,对于你正在处理的单子,是否存在这样一个函数。如果有,检查任何潜在的陷阱——它是否会产生运行时错误或导致奇怪的行为
在您的情况下,如果您完全确定可能
从来都不是无
,请使用fromJust
。然而,这通常不是一个好的实践,因此您应该坚持使用模式匹配Maybe
的值。答案取决于您是否需要同时使用Maybe和IO monad,还是单独使用
如果您需要同时使用它们-答案是您需要通过构建包含IO monad和MaybeT monad transformer的monad transformer堆栈来组合IO
和Maybe
monad
如果您需要单独使用,则可以使用更简单的解决方案:
import System.Environment
import Data.List
main = getArgs >>= (\args -> return (elemIndex "-p" args
>>= \y -> return $ y + 900) >>= print)
注意返回值
。因此,您在内部parentneses中有可能单子(介于elemIndex
和900
之间),但没有IO。也就是说,您不能在离开monad之前执行IO操作,正如我在print中所显示的那样