Scala 什么时候应该使用应用程序而不是monad?
我一直在工作中使用Scala,为了更深入地理解函数式编程,我选择了Graham Hutton在Haskell中的编程(爱它:) 在单子一章中,我第一次了解了应用函子(AFs)的概念 在我(有限的)专业Scala能力范围内,我从未使用过AFs,并且总是编写使用Monad的代码。我试图提炼出对“何时使用AFs”的理解,从而引出这个问题。这一观点正确吗: 如果您的所有计算都是独立且可并行的(即,一个计算的结果并不决定另一个计算的输出),那么如果输出需要通过管道传输到纯函数而不产生任何影响,那么AF将更好地满足您的需要。然而,如果你只有一个依赖项,AFs也帮不上忙,你将被迫使用单子。如果输出需要通过管道传输到具有效果的函数(例如,可能返回),则需要单子 例如,如果您有这样的“一元”代码:Scala 什么时候应该使用应用程序而不是monad?,scala,haskell,monads,applicative,Scala,Haskell,Monads,Applicative,我一直在工作中使用Scala,为了更深入地理解函数式编程,我选择了Graham Hutton在Haskell中的编程(爱它:) 在单子一章中,我第一次了解了应用函子(AFs)的概念 在我(有限的)专业Scala能力范围内,我从未使用过AFs,并且总是编写使用Monad的代码。我试图提炼出对“何时使用AFs”的理解,从而引出这个问题。这一观点正确吗: 如果您的所有计算都是独立且可并行的(即,一个计算的结果并不决定另一个计算的输出),那么如果输出需要通过管道传输到纯函数而不产生任何影响,那么AF将更
val result = for {
x <- callServiceX(...)
y <- callServiceY(...) //not dependent on X
} yield f(x,y)
- 如果
AFs将为您提供更好的服务f==pure和callService*是独立的
- 如果
有效果,即f
您将需要单子f(x,y):选项[Response]
- 如果
callServiceX(…),y这里没有真正的决策:始终使用应用程序接口,除非它太弱。1 这是抽象强度的基本张力:更多的计算可以用Monad表示;用Applicative表示的计算可以以更多的方式使用 关于使用Monad的条件,您似乎基本上是正确的。我不确定这一点:
- 如果
有效果,即f
您将需要单子f(x,y):选项[Response]
,则没有任何东西可以阻止您创建F
。但是就像以前一样,您将无法在F[Option[X]]
中根据F
-选项是否成功做出进一步的决定--
操作的整个“调用树”必须是可以知道的,而无需计算任何值F
撇开可读性问题不谈,也就是说。一元代码可能更容易被来自传统背景的人所接受,因为它的强制性外观。我认为您需要对“独立”或“并行化”或“依赖性”等术语保持谨慎。例如,在IO单元格中,考虑计算:foo :: IO (String, String) foo = do line1 <- getLine line2 <- getLine return (line1, line2)
作为一个更现实的示例,表达式λ> [(1+),(10+)] <*> [3,4,5] [4,5,6,13,14,15]
的一元解析器可能如下所示:3+4
expr :: Parser Expr expr = do x <- factor op <- operator y <- factor return $ x `op` y
或者,考虑这个“代码>状态INT/<代码>动作:
我不确定是否有一种直观的方式来思考这个问题。粗略地说,如果您认为一元操作/计算bar :: Int -> Int -> State Int Int bar x y = do put (x + y) z <- gets (2*) return z
具有“一元结构”ma
以及“值结构”m
,那么应用程序会将一元结构和值结构分开。例如,应用计算:a
foo :: IO (String, String) foo = do line1 <- getLine line2 <- getLine return (line1, line2)
λ> [(1+),(10+)] <*> [3,4,5] [4,5,6,13,14,15]
我们不能写下独立于值的结构列表计算。列表结构(例如,最终列表的长度)取决于值级别数据(列表中的实际值
)。这是一种需要monad而不是applicative的依赖关系。至少在Haskell中,有一种语言扩展,允许您使用[1,2,3]
构造编写代码,但是编译器会确定是否可以将其删除为使用do
实例而不是applicative
实例。主要目标是确定何时可以安全地并行代码;我不确定是否还有其他编译器级别的原因让我更喜欢其中一个。我在2013年写的这个答案仍然是相关的:Re your footnote,monad
是否基本上让它们看起来一样?@Joseph原则上说。但我讨厌那个扩展,它不能可靠地工作。(例如,它不知道如何处理ApplicativeDo
)这很有用。我对“独立”和“可并行化”这两个词的选择显然是次优的,仅用作传达意图的近似值,缺乏最能解释我的困惑的相关领域词汇。另一方面,一元计算允许一元结构依赖于值结构let
一种应用计算代码>?
bar x y = put (x + y) *> gets (2*)
λ> [(1+),(10+)] <*> [3,4,5] [4,5,6,13,14,15]
[f,g] <*> [a,b,c] = [f a, f b, f c, g a, g b, g c]
quux :: [Int] quux = do n <- [1,2,3] drop n [10..15]
- 如果