Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/scala/19.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Scala 什么时候应该使用应用程序而不是monad?_Scala_Haskell_Monads_Applicative - Fatal编程技术网

Scala 什么时候应该使用应用程序而不是monad?

Scala 什么时候应该使用应用程序而不是monad?,scala,haskell,monads,applicative,Scala,Haskell,Monads,Applicative,我一直在工作中使用Scala,为了更深入地理解函数式编程,我选择了Graham Hutton在Haskell中的编程(爱它:) 在单子一章中,我第一次了解了应用函子(AFs)的概念 在我(有限的)专业Scala能力范围内,我从未使用过AFs,并且总是编写使用Monad的代码。我试图提炼出对“何时使用AFs”的理解,从而引出这个问题。这一观点正确吗: 如果您的所有计算都是独立且可并行的(即,一个计算的结果并不决定另一个计算的输出),那么如果输出需要通过管道传输到纯函数而不产生任何影响,那么AF将更

我一直在工作中使用Scala,为了更深入地理解函数式编程,我选择了Graham Hutton在Haskell中的编程(爱它:)

在单子一章中,我第一次了解了应用函子(AFs)的概念

在我(有限的)专业Scala能力范围内,我从未使用过AFs,并且总是编写使用Monad的代码。我试图提炼出对“何时使用AFs”的理解,从而引出这个问题。这一观点正确吗:

如果您的所有计算都是独立且可并行的(即,一个计算的结果并不决定另一个计算的输出),那么如果输出需要通过管道传输到纯函数而不产生任何影响,那么AF将更好地满足您的需要。然而,如果你只有一个依赖项,AFs也帮不上忙,你将被迫使用单子。如果输出需要通过管道传输到具有效果的函数(例如,可能返回),则需要单子

例如,如果您有这样的“一元”代码:

val result = for {
 x <- callServiceX(...)
 y <- callServiceY(...) //not dependent on X 
} yield f(x,y)
  • 如果
    f==pure和callService*是独立的
    AFs将为您提供更好的服务
  • 如果
    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]
    

    我们不能写下独立于值的结构列表计算。列表结构(例如,最终列表的长度)取决于值级别数据(列表中的实际值
    [1,2,3]
    )。这是一种需要monad而不是applicative的依赖关系。

    至少在Haskell中,有一种语言扩展,允许您使用
    do
    构造编写代码,但是编译器会确定是否可以将其删除为使用
    applicative
    实例而不是
    monad
    实例。主要目标是确定何时可以安全地并行代码;我不确定是否还有其他编译器级别的原因让我更喜欢其中一个。我在2013年写的这个答案仍然是相关的:Re your footnote,
    ApplicativeDo
    是否基本上让它们看起来一样?@Joseph原则上说。但我讨厌那个扩展,它不能可靠地工作。(例如,它不知道如何处理
    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]