【发布时间】:2020-06-16 12:04:29
【问题描述】:
我正在阅读 Graham Hutton 的《Haskell 编程》,对下面概述的思路感到困惑。
他使用下面的示例来鼓励使用 monad,通过展示应用函子在返回类型为 Maybe 的除法运算中的缺点来处理指示可能除以零的错误情况 em> 场景。
给定:
data Expr = Val Int | Div Expr Expr
safediv :: Int -> Int -> Maybe Int
safediv _ 0 = Nothing
safediv n m = Just (n `div` m)
eval :: Expr -> Maybe Int
eval (Val n) = pure n --type: Just(n)?
eval (Div x y) = pure safediv <*> eval x <*> eval y --type: Maybe(Maybe Int)?
他继续解释:
但是,此定义类型不正确。特别是, 函数
safediv的类型为Int->Int->Maybe Int,而在 以上上下文需要Int->Int->Int类型的函数。用自定义函数替换
pure safediv没有帮助 要么,因为这个函数需要有类型Maybe(Int->Int->Int),它不提供任何指示方式 当第二个整数参数为零时失败。 (十)结论是函数
eval不符合 由应用函子捕获的有效编程。这 应用风格限制了我们将纯函数应用于 有效的论点:eval不适合这种模式,因为 用于处理结果值的函数safediv不是 一个纯函数,但它本身可能会失败。
我不是 Haskell 程序员,但从 eval (Div x y) 的类型来看,它似乎是 Maybe(Maybe Int) 的类型 - 可以简单地压扁,不是吗? (类似于 Scala 中的 flatten 或 Haskell 中的 join)。 真正的问题是什么?
无论x,y 是否为Just(s)/Nothing(s),似乎safediv 都会正确评估——这里唯一的问题是可以适当转换的返回类型。作者究竟是如何从他的论点得出这个结论的,这是我很难理解的。
...applicative style 限制了我们将纯函数应用于有效参数
另外,为什么上面标有(X) 的段落在问题似乎是或返回类型不对齐时会做出这样的声明。
我知道应用程序可用于更有效地链接计算,其中一个的结果不会影响另一个 - 但在这种情况下,我对失败的发生方式/位置以及是否只是简单的返回感到困惑类型修复将解决问题:
eval (Div x y) = join(pure safediv <*> eval x <*> eval y)
safediv 必须是纯粹的吗? AFAIK 它也可以是F[Maybe] 或F[Either] 类型,不是吗?我可能会错过什么?我可以看到他要去哪里,但不确定这是否是到达那里的正确示例,恕我直言。
【问题讨论】:
-
应用程序没有
join的概念。要获得join,您需要一个单子。这就是重点:applicatives 还不够,你需要一个 monad。 -
换一种说法:当你的数据类型有
join(在Applicative Functor的其他东西之上)时,它是一个Monad。
标签: haskell functional-programming