Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/10.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
在javascript函数中使用函数式Haskell类累加器_Javascript_Haskell_Underscore.js_Lodash_Ramda.js - Fatal编程技术网

在javascript函数中使用函数式Haskell类累加器

在javascript函数中使用函数式Haskell类累加器,javascript,haskell,underscore.js,lodash,ramda.js,Javascript,Haskell,Underscore.js,Lodash,Ramda.js,我目前正在研究Haskell,我对它的一些特性很感兴趣,例如使用累加器的结束递归函数 问题: javascript中是否有类似的构造?甚至是 考虑到效率是有意义的,因为javascript不是 像哈斯凯尔一样有用吗 有像拉姆达、洛达斯这样的图书馆吗。。。这就支持了这种方式 编程语言 如果是这样,您将如何用javascript编写此示例: power_acc :: Double -> Int -> Double power_acc x y = power_acc_h x y 1

我目前正在研究Haskell,我对它的一些特性很感兴趣,例如使用累加器的结束递归函数

问题:

  • javascript中是否有类似的构造?甚至是 考虑到效率是有意义的,因为javascript不是 像哈斯凯尔一样有用吗
  • 有像拉姆达、洛达斯这样的图书馆吗。。。这就支持了这种方式 编程语言
  • 如果是这样,您将如何用javascript编写此示例:

     power_acc :: Double -> Int -> Double
     power_acc x y = power_acc_h x y 1
    
     power_acc_h :: Double -> Int -> Double -> Double
     power_acc_h x 0 acc = acc
     power_acc_h x y acc = power_acc_h x (y-1) (acc*x)
    

  • 这是javascript中Haskell代码的直接翻译:

    function power_acc(x, y) {
        return aux(x,y,1);
        function aux(x, y, acc) {
            if (y == 0)
                return acc;
            else
                return aux(x, y-1, acc*x);
        }
    }
    
    有像拉姆达、洛达斯这样的图书馆吗。。。这就支持了这一点 编程方式

    你不需要洛达斯或拉姆达。你可以用你的电脑来做 纯javascript,正如我上面所示。还要注意的是,lodash是 一个实用程序库,为操作提供一致的API 以功能性的方式收集。在这些情况下,它对您没有帮助

    javascript中是否有类似的构造

    是的,您可以直接将其转换为JS:

    function power_acc(x, y) { // Double -> Int -> Double
        y = y>>>0; // cast to positive int (avoiding nontermination)
        return power_acc_h(x, y, 1);
    }
    function power_acc_h(x, y, acc) { // Double -> Int -> Double -> Double
        return y == 0
          ? acc
          : power_acc_h(x, y-1, acc*x);
    }
    
    或者,由于javascript的功能不如Haskell,它在效率方面是否有意义


    在ES6中,JS完全支持尾部递归,您将获得与循环相同的效率(甚至可能比haskell更好,因为您不创建惰性乘法)

    有像拉姆达、洛达斯这样的图书馆吗。。。它支持这种编程方式

    不需要图书馆。尽管我确信有一些lib可以简化类型检查或为模式匹配提供更好的表示法

    您将如何用javascript编写这个示例

    您将使用
    while
    循环。haskell中的所有累积函数都是以这种方式编写的,因为它们可以直接优化为循环,这是JS中这个构造应该使用的符号(大多数程序员都很熟悉):


    变异局部变量没有坏处,您的函数仍然是纯函数。如果您想寻找更短的表示法,请使用
    for
    循环。

    除了Sibi的答案之外,我想指出javascript(至少是nodejs)实际上分配堆栈空间。当指数达到13000左右时,它运行良好且快速,然后您将得到
    范围错误:超过了最大调用堆栈大小
    。要进行此实验,您需要将基数设置为接近1的数字(例如1.0001),否则将得到无穷大

    哈斯凯尔没有这个问题。1000倍大的指数(即13000000)仍然不会导致任何空间问题,尽管它确实需要几秒钟才能运行。这是因为递归是尾部调用,它们在haskell的常量空间中运行


    因此,在某种程度上,Sibi的回答模仿了Haskell的表达能力,但它仍然表现出不同的运行时行为。我认为你对此无能为力。

    我同意所有的答案,图书馆既不是必需的,也不是特别有用的。(顺便说一句,我是《拉姆达》的作者之一。)

    Bergi到JS的翻译很好,尽管我认为至少在浏览器端JS中,将helper函数嵌入到局部闭包中更为惯用,这与Sibi的答案有点接近

    Martin Drautzburg指出性能问题的原因是,尽管尾部调用优化,但它无处不在。一个例外是Babel对直接递归的支持,因此Babel Transpile版本应该获得预期的性能优势

    因此,如果您想这样做是因为它的优雅,因为您相信TCO很快就会出现,如果您不担心当前可能出现的性能问题,那么这些响应是有用的,我甚至会在组合中加入一种ES6技术:

    // Double -> Int -> Double -> Double
    function powerAcc(x, y, acc = 1) {
        return y == 0 ? acc : powerAcc(x, y - 1, acc * x);
    }
    
    powerAcc(2, 5); //=> 32
    

    帮助替换这种语言中一些简单的模式匹配形式,因为这种语言没有真正的模式匹配。这仍然依赖于TCO,但会使代码更加干净。它也应该在Babel中运行良好。

    我的2美分:尽管我非常喜欢函数式编程,但我发现习惯用法累加器+递归对于有状态的
    for
    循环来说是一种不太雅观的编码。在命令式语言中,我更喜欢循环而不是FP习语。当然,有时这样的循环实际上是折叠的,如在发布的示例中,在这种情况下,我发现对于
    s或累加器,FP高阶折叠比
    更优雅。当然,所有这些都只是个人喜好的问题。“对于ES6,JS完全支持尾部递归”。。。然而,这是真的。@ScottSauyet:真的(巴贝尔除外)。使用惯用循环的另一个原因是:-)
    
    // Double -> Int -> Double -> Double
    function powerAcc(x, y, acc = 1) {
        return y == 0 ? acc : powerAcc(x, y - 1, acc * x);
    }
    
    powerAcc(2, 5); //=> 32