gpt4 book ai didi

performance - 只有一个参数函数有效吗? haskell

转载 作者:行者123 更新时间:2023-12-03 15:41:17 25 4
gpt4 key购买 nike

我已经开始学习 Haskell 并且我已经读到 Haskell 中的每个函数都只接受一个参数,我无法理解 Haskell 引擎盖下发生的魔法使之成为可能,我想知道它是否有效。
例子

>:t (+)
(+) :: Num a => a -> a -> a
以上签名表示 (+)函数需要一个 Num然后返回另一个函数,它接受一个 Num并返回 Num
示例 1 相对容易,但我开始想知道当函数有点复杂时会发生什么。
我的问题

为了这个例子,我写了一个 zipWith函数并以两种方式执行它,一次传递一个参数,一次传递所有参数。
zipwithCustom f (x:xs) (y:ys) = f x y : zipwithCustom f xs ys
zipwithCustom _ _ _ = []
zipWithAdd = zipwithCustom (+)
zipWithAddTo123 = zipWithAdd [1,2,3]

test1 = zipWithAddTo123 [1,1,1]
test2 = zipwithCustom (+) [1,2,3] [1,1,1]

>test1
[2,3,4]
>test2
[2,3,4]
  • 一次传递一个参数(scenario_1)是否与一次传递所有参数(scenario_2)一样有效?
  • 这些场景与 Haskell 实际执行的计算有什么不同吗test1test2 (除了场景_1 可能需要更多内存,因为它需要保存 zipWithAddzipWithAdd123 )
  • 这是正确的,为什么?在场景_1 中,我迭代了 [1,2,3]然后结束 [1,1,1]
  • 这是正确的,为什么?在场景_1 和场景_2 中,我同时遍历两个列表

  • 我意识到我在一篇文章中提出了很多问题,但我相信这些问题是相互关联的,并将帮助我(以及其他不熟悉 Haskell 的人)更好地了解 Haskell 中实际发生的情况,从而使这两种情况都成为可能。

    最佳答案

    您询问“Haskell”,但 Haskell 语言规范并不关心这些细节。选择如何进行评估取决于实现 - 规范唯一说明的是评估结果应该是什么,并小心避免给出必须用于计算该结果的算法。所以在这个答案中,我将讨论 GHC,实际上,它是唯一现存的实现。
    对于(3)和(4),答案很简单:无论您是否应用 zipWithCustom,迭代模式都完全相同。一次争论一个或一次全部争论。 (并且该迭代模式是一次迭代两个列表。)
    不幸的是,(1)和(2)的答案是 复杂 .
    起点是以下简单算法:

  • 当您将函数应用于参数时,会创建(分配和初始化)一个闭包。闭包是内存中的一种数据结构,包含一个指向函数的指针和一个指向参数的指针。当函数体被执行时,只要提到它的参数,就会在闭包中查找该参数的值。
  • 就是这样。

  • 然而,这种算法有点糟糕。这意味着如果你有一个 7 个参数的函数,你分配了 7 个数据结构,当你使用一个参数时,你可能必须沿着一个 7 长的指针链来找到它。总的。所以 GHC 做了一些更聪明的事情。它以一种特殊的方式使用你的程序的语法:如果你将一个函数应用于多个参数,它只会为该应用程序生成一个闭包,字段与参数一样多。
    (嗯……这可能不太正确。实际上,它跟踪每个函数的元数——以句法方式再次定义为定义该函数时 = 符号左侧使用的参数数量。如果您将函数应用于比其数量更多的参数,您可能会得到多个闭包或其他东西,我不确定。)
    所以这很好,因此您可能会认为您的 test1test2 相比,将分配一个额外的闭包.你是对的......当优化器没有打开时。
    但是 GHC 也做了很多优化工作,其中之一就是注意“小”定义并将它们内联。几乎可以肯定,打开优化后,您的 zipWithAddzipWithAddTo123两者都将在任何使用它们的地方内联,我们将回到只分配一个闭包的情况。
    希望这个解释能让你自己回答问题 (1) 和 (2),但以防万一,这里有明确的答案:
    1. Is passing one argument at the time as efficient as passing all arguments at once?

    也许。一次传递一个参数可能会通过内联转换为一次传递所有参数,然后当然它们将是相同的。在没有这种优化的情况下,与一次传递所有参数相比,一次传递一个参数会带来(非常轻微的)性能损失。
    1. Are those scenarios any different in terms of what Haskell is actually doing to compute test1 and test2?
    test1test2几乎肯定会被编译为相同的代码——甚至可能只编译其中一个,另一个是它的别名。
    如果你想阅读更多关于实现中的想法, Spineless Tagless G-machine论文比其标题所暗示的要平易近人,而且只是有点过时。

    关于performance - 只有一个参数函数有效吗? haskell ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65619588/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com