2012-03-28 43 views
3

(真的strugging所有权这个问题,因此,如果任何人有意见了自由。)当在underscore.js中链接操作(如map reduce)时,有没有提供最终转换方法的方法?

说我想要做这样的操作:

  • 采取数组[1,2,3]
  • 由2(地图)乘以每个元素:[2,4,6]
  • 添加元素一起(减少):120
:12
  • 乘以10的结果

    我可以在下划线使用链接做到这一点很干净,像这样:

    arr = [1,2,3] 
    map = (el) -> 2*el 
    reduce = (s,n) -> s+n 
    out = (r) -> 10*r 
    
    reduced = _.chain(arr).map(map).reduce(reduce).value() 
    result = out(reduced) 
    

    但是,如果我能链中的“出”的方法也一样,这样的话会更好:

    result = _.chain(arr).map(map).reduce(reduce).out(out).value() 
    

    现在这将是一个相当简单的补充库,如下划线。但我的问题是:

    • 此'out'方法在函数式编程中有一个名称吗?
    • 这是否已经存在于下划线(tap接近,但不完全)。
  • +0

    您是否看到此线程https://github.com/documentcloud/underscore/pull/499?如果你有一个很好的现实世界的例子,你可以试着问Jeremy为什么他这个拉请求是不合适的。 – Karolis 2012-03-28 21:52:38

    +0

    什么是' - >'语法? – Marcin 2012-04-23 17:40:27

    +0

    Hi @Marcin,道歉,那就是CoffeeScript。 '(r) - > 10 * r'与'function(r){return 10 * r; }' – latentflip 2012-04-24 09:15:31

    回答

    3

    这个问题让我颇感兴趣。这是我的一些想法。

    感觉就像在'chain()模式中使用underscore.js'脱离了函数式编程范例。基本上,不是在函数上调用函数,而是以OOP方式调用包装对象实例的方法。

    我自己在这里和那里使用underscore's chain(),但这个问题让我想到了。如果最好简单地创建更有意义的函数,然后可以按顺序调用,而不必使用chain()。然后,您的例子是这个样子:

    arr = [1,2,3] 
    double = (arr) -> _.map(arr, (el) -> 2 * el) 
    sum = (arr) -> _.reduce(arr, (s, n) -> s + n) 
    out = (r) -> 10 * r 
    
    result = out sum double arr 
    # probably a less ambiguous way to do it would be 
    result = out(sum(double arr)) 
    

    在真正的函数式编程语言展望(如..不是JavaScript更多功能),似乎你可以做完全有同样的事情在一个更简单的方式。这是用标准ML编写的相同程序。请注意,只有一个参数调用map会返回另一个函数。没有必要像在JavaScript中那样将这个映射封装在另一个函数中。

    val arr = [1,2,3]; 
    val double = map (fn x => 2*x); 
    val sum = foldl (fn (a,b) => a+b) 0; 
    val out = fn r => 10*r; 
    
    val result = out(sum(double arr)) 
    

    标准ML还允许您创建运营商,这意味着我们可以作出这样可以用来调用这些函数以更直观的顺序有点“链”操作。

    infix 1 |>; 
    fun x |> f = f x; 
    
    val result = arr |> double |> sum |> out 
    

    我也觉得这underscore.js链具有类似于函数式编程单子的东西,但我不知道很多关于这些。尽管如此,我感觉这种数据处理流水线并不是您通常使用monads来处理的东西。

    我希望具有更多功能编程经验的人可以切入并纠正我,如果我在上面的任何一点上都错了。

    UPDATE

    略有下车的话题,但一个的方式创造的部分功能可能是以下几点:

    // extend underscore with partialr function 
    _.mixin({ 
        partialr: function (fn, context) { 
        var args = Array.prototype.slice.call(arguments, 2); 
        return function() { 
         return fn.apply(context, Array.prototype.slice.call(arguments).concat(args)); 
        }; 
        } 
    }); 
    

    此功能现在可以用于从任何下划线函数创建一个部分功能,因为他们大多数将输入数据作为第一个参数。例如,SUM函数现在可以像

    var sum = _.partialr(_.reduce, this, function (s, n) { return s + n; }); 
    sum([1,2,3]); 
    

    我还是喜欢创建ARR |>双|>和|>出过了(SUM(双(ARR)))虽然。 Underscore的链()很好,因为它读取更自然的顺序。

    +0

    Cheers @Karolis,很好的发现我的方法并没有实际的功能,因为是的,即使是文档调用'chain()模式'使用下划线的OO方式。 – latentflip 2012-03-28 22:29:04

    +0

    我更喜欢你的新方法。好想法:) – latentflip 2012-03-28 22:33:15

    +0

    我希望创建这些小功能的想法更容易。特别是在vanilla JavaScript中,写入像(arr) - > _.map(arr,(el) - > 2 * el)这样的smr有点冗长。我正在研究如何_.compose或_.bind或部分或咖喱可以帮助,但不能完全钉它.. – Karolis 2012-03-28 22:47:11

    2

    就您所寻找的名称而言,我认为您所要做的仅仅是一种函数应用程序的形式:您有一个下划线对象,并且您希望将函数应用于其值。在下划线,你可以将其定义是这样的:

    _.mixin({ 
        app: function(v, f) { return f (v); } 
    }); 
    

    ,那么你几乎可以做你的要求为:

    var arr = [1,2,3]; 
    function m(el) { return 2*el; }; 
    function r(s,n) { return s+n; }; 
    function out(r) { return 10*r; }; 
    
    console.log("result: " + _.chain(arr).map(m).reduce(r).app(out).value())); 
    

    说了这么多,我想使用类似SML使传统的类型化函数式编程语言这种想法很多,为功能组合提供了更轻量级的语法。 Underscore在函数式编程方面做了一些jquery转换,我不确定我在想什么;但没有静态类型的检查,很容易犯错误!

    相关问题