Haskell 返回不同类型的函数中单子的Do表示法
有没有一种方法可以在返回类型不是所述monad的函数中为monad编写Haskell 返回不同类型的函数中单子的Do表示法,haskell,monads,maybe,Haskell,Monads,Maybe,有没有一种方法可以在返回类型不是所述monad的函数中为monad编写do符号 我有一个main函数来完成代码的大部分逻辑,并用另一个函数来补充,在中间进行一些计算。补充函数可能会失败,这就是它返回Maybe值的原因。我希望对main函数中的返回值使用do表示法。举一个一般性的例子: -- does some computation to two Ints which might fail compute :: Int -> Int -> Maybe Int -- actual l
do
符号
我有一个main函数来完成代码的大部分逻辑,并用另一个函数来补充,在中间进行一些计算。补充函数可能会失败,这就是它返回
Maybe
值的原因。我希望对main函数中的返回值使用do
表示法。举一个一般性的例子:
-- does some computation to two Ints which might fail
compute :: Int -> Int -> Maybe Int
-- actual logic
main :: Int -> Int -> Int
main x y = do
first <- compute x y
second <- compute (x+2) (y+2)
third <- compute (x+4) (y+4)
-- does some Int calculation to first, second and third
--对可能失败的两个整数进行一些计算
计算::Int->Int->Maybe Int
--实际逻辑
main::Int->Int->Int
main x y=do
首先,签名本质上是错误的。结果应该是可能是Int
:
main :: Int -> Int -> Maybe Int
main x y = do
first <- compute x y
second <- compute (x+2) (y+2)
third <- compute (x+4) (y+4)
return (first + second + third)
这意味着它确实会从数据构造函数中“解包”值,但是如果没有任何内容
,那么这意味着整个do
块的结果将是没有任何内容
这或多或少是Monad提供的便利:您可以将计算作为一系列成功的操作进行,如果其中一个操作失败,结果将是无任何结果
,否则将是仅结果
因此,您不能在最后返回一个Int
而不是Maybe Int
,因为从类型的角度来看,一个或多个计算完全可能返回一个Nothing
但是,如果您添加一个“默认”值,该值将在其中一个计算为Nothing
的情况下使用,则可以“post”处理do
块的结果,例如:
import Data.Maybe(fromMaybe)
main :: Int -> Int -> Int
main x y = fromMaybe 0 $ do
first <- compute x y
second <- compute (x+2) (y+2)
third <- compute (x+4) (y+4)
return (first + second + third)
请注意,asum
仍然只能包含无
s,因此您仍然需要进行一些后处理。Willem的答案基本上是完美的,但为了真正阐明这一点,让我们考虑一下如果您可以编写允许返回int的内容,将会发生什么
因此,您有类型为Int->Int->Int
的main
函数,让我们假设您的compute
函数的实现如下:
compute :: Int -> Int -> Maybe Int
compute a 0 = Nothing
compute a b = Just (a `div` b)
现在,这基本上是整数除法函数的安全版本div::Int->Int->Int
,如果除数为0
,则返回Nothing
如果可以编写返回Int
的主函数,则可以编写以下内容:
unsafe :: Int
unsafe = main 10 (-2)
这将使成为第二个我对你的问题有两种解释,因此要回答这两种解释:
将可能是Int
的值相加,得到Int
要在抛出Nothing
值时求和可能是Int
s,可以使用sum
从列表中抛出Nothing
值:
sum . catMaybes $ [compute x y, compute (x+2) (y+2), compute (x+4) (y+4)]
获取第一个可能是Int
值,该值仅为n
,作为Int
要获取第一个非Nothing
值,您可以使用catMaybes
与组合来获取Just
第一个值(如果有)或Nothing
第一个值(如果没有),并将Nothing
转换为默认值:
fromMaybe 0 . listToMaybe . catMaybes $ [compute x y, compute (x+2) (y+2), compute (x+4) (y+4)]
如果保证至少有一个成功,请改用head
:
head . catMaybes $ [compute x y, compute (x+2) (y+2), compute (x+4) (y+4)]
关键是,这些计算可能也会产生一个,如果不是,您可以使用返回值。不确定您指的是什么,compute
或main
?无论哪种方式,compute
已经返回了一个Maybe
值,而main
旨在明确返回一个Int
,因此没有Maybe
。换句话说,main
中的一个计算可能失败,但至少应该有一个通过,这保证了main
具有Int
返回值。但是Monad Maybe
的思想是将Maybe
视为“潜在失败”计算。因此,在这里,您创建了一个潜在失败计算的“链”,如果成功,则返回Just result
,否则返回Nothing
。如果你确定compute
总是返回一个Just
,那么为什么它的签名是Int->Int->Maybe Int
?谢谢,你的评论将它称为一系列成功的操作,这让我更清楚,我意识到我实际上走错了方向。我的意图不是让它成为一系列的动作,而是一系列的计算(任何一个都可能失败,但有一个肯定会通过),并返回通过的系列中的第一个。本质上,main
所做的是抽象出可能的失败,并选择第一个成功的,这样当调用main
时,一个明确的Int
值可以在其他地方使用。有什么方法可以做到这一点吗?@lookarpstars:你可以使用asum
,比如asum[computexy,compute(x+2)(y+2)]
,它将返回列表中的第一个,但这仍然是一个可能
,因为所有计算都可能失败。请参阅:Sweet,这个评论和你在编辑后添加的部分给了我一些工作的依据。感谢您简洁的回答。@lookarpstars对于您的第一条评论,不,主要不是“选择第一条成功的”。只有当所有三个计算都成功时,它才会返回一个Just(三个结果之和)。否则它什么也不返回。因此,它尝试运行所有这些操作(一个接一个,但都是),然后合并所有结果。
fromMaybe 0 . listToMaybe . catMaybes $ [compute x y, compute (x+2) (y+2), compute (x+4) (y+4)]
head . catMaybes $ [compute x y, compute (x+2) (y+2), compute (x+4) (y+4)]