8

私がいくつかの機能を持っているとしましょう:

function g(a,b,c){ return a + b + c }

そして、それを「カリー化された」形式に変えたいと思います(それ自体は正確にカリー化されていないため、引用で):

function h(a,b,c){

    switch(true){

        case (a !== undefined && b !== undefined && c !== undefined):
            return a + b + c

        case (a !== undefined && b !== undefined && c === undefined): 
            return function(c){ return a + b + c }

        case (a !== undefined && b == undefined  && c === undefined ):
            return function(b,c){
                return (c === undefined) ? function(c){ return a + b + c } : a + b + c
            }

        default:
            return h

    }

}

上記のフォームには、私が望む部分バインディングの動作があります。

h(1)     -> h(b,c)
h(1,2)   -> h(c)
h(1,2,3) -> 6
h()      -> h(a,b,c)

curryここで、このプロセスをいくつかの汎用関数に自動化して、カリー化されていない関数 (およびおそらくそのパラメーターの数) を指定すると、上記の関数が生成されるようにしたいと考えています。しかし、それを実装する方法がよくわかりません。

または、次のフォームが自動的に作成されると、それも興味深いでしょう。

function f(a,b,c){
    return function(a){ return function(b){ return function(c){ return a + b + c }}}
}

バインディングfは次のようになりますが:

f(1)(2)(3) = 6

そのため、非常に扱いにくく、慣用的ではありませんが、上記のフォームを作成する方が実現可能に思えます。

上記のフォームのいずれかが何らかの関数によって生成される可能性があります。

4

5 に答える 5

3

これが私の試みです:

function curry(fn, len) {
    if (typeof len != "number")
        len = fn.length; // getting arity from function
    return function curried() {
        var rlen = len - arguments.length;
        if (rlen <= 0) // then execute now
            return fn.apply(this, arguments);
        // else create curried, partially bound function:
        var bargs = [this]; // arguments for `bind`
        bargs.push.apply(bargs, arguments);
        return curry(fn.bind.apply(fn, bargs), rlen);
    };
}

これは部分適用ではなく (JS ではbindmethodを使用すると簡単です)、真の関数型カリー化です。これは、アリティが固定されている任意の関数で動作します。可変引数関数の場合、別の実行トリガーが必要になります。おそらく、引数が渡されなくなった場合や、exec@ plalx の回答のようなメソッドが必要になる場合があります。

于 2013-09-28T14:39:03.510 に答える
0

このようなものはどうですか:

function makeLazy(fn) {
    var len = fn.length;
    var args = [];
    return function lazy() {
        args.push.apply(args, arguments);
        if (args.length < len) {
            return lazy;
        } else {
            return fn.apply(this, args);
        }
    }
}

function f(a,b,c) { return a + b + c; }

var lazyF = makeLazy(f);
lazyF(1)(2)(3); // 6

var lazyF = makeLazy(f);
lazyF(1,2)(3); // 6

再利用可能な関数が必要な場合(何が必要か正確にはわかりません)、これは機能します:

function makeCurry(fn) {
    return function curry() {
        var args = [].slice.call(arguments);
        return function() {
            return fn.apply(this, args.concat.apply(args, arguments));
        };
    }
}


function f(a,b,c) { return a + b + c; }

var curryF = makeCurry(f);
var addOneTwoAnd = curryF(1,2);

addOneTwoAnd(3); // 6
addOneTwoAnd(6); // 9
于 2013-09-27T03:37:43.423 に答える