web-dev-qa-db-ja.com

可変カレー和関数

このように機能するには、js sum関数が必要です。

_sum(1)(2) = 3
sum(1)(2)(3) = 6
sum(1)(2)(3)(4) = 10 
etc.
_

出来ないと聞きました。しかし、sumの前に_+_を追加すれば実行できると聞きました。 +sum(1)(2)(3)(4)のように。
これを行う方法のアイデアはありますか?

29

私があなたが何を望んでいるか理解しているかどうかはわかりませんが、

function sum(n) {
  var v = function(x) {
    return sum(n + x);
  };

  v.valueOf = v.toString = function() {
    return n;
  };

  return v;
}

console.log(+sum(1)(2)(3)(4));

JsFiddle

62
Rafael

これは、最後の呼び出しで空の角かっこを閉じるキーとして使用する例です(前回のインタビューから)。

合計(1)(4)(66)(35)(3)()

function sum(numberOne) {
  var count = numberOne;
  return function by(numberTwo) {
    if (numberTwo === undefined) {
      return count;
    } else {
      count += numberTwo;
      return by;
    }
  }
}
console.log(sum(1)(4)(66)(35)(3)());
15
yury.hrynko

コメントとして残すだけの評判がまだないので、この改訂版を独自の投稿として投稿しています。これは@Rafaelの優れたソリューションの改訂版です。

function sum (n) {
    var v = x => sum (n + x);
    v.valueOf = () => n; 
    return v;
}

console.log(+sum(1)(2)(3)(4)); //10

V.toStringビットを保持する理由は、必要と思われなかったためわかりませんでした。エラーが発生した場合は、コメントでv.toStringが必要な理由を教えてください(v.toStringがなくてもテストに合格しました)。読みやすくするために、残りの無名関数を矢印関数に変換しました。

6
Brad

これは、@ Vembaと同様に、ES6とtoStringを使用するソリューションです。

function add(a) {
  let curry = (b) => {
    a += b
    return curry
  }
  curry.toString = () => a
  return curry
}

console.log(add(1))
console.log(add(1)(2))
console.log(add(1)(2)(3))
console.log(add(1)(2)(3)(4))
1
Artokun

ES6 Javascriptの汎用可変カレー関数を使用した解決策を次に示します。ただし、引数を呼び出すには最後の_()_が必要です。

_const curry = (f) =>
   (...args) => args.length? curry(f.bind(0, ...args)): f();
_
_const sum = (...values) => values.reduce((total, current) => total + current, 0)
curry(sum)(2)(2)(1)() == 5 // true
_

@ rafael's answer のようにvalueOfを使用して、_()_を必要としない別の例を次に示します。 valueOfをこのように(またはおそらくまったく)使用することは、コードを読んでいる人にとって非常に混乱しますが、それぞれ独自のものです。

その答えのtoStringは不要です。内部的には、JavaScriptが型強制変換を実行する場合、常にvalueOf()を呼び出す前にtoString()を呼び出します。

_
// invokes a function if it is used as a value
const autoInvoke = (f) => Object.assign(f, { valueOf: f } );

const curry = autoInvoke((f) =>
   (...args) => args.length? autoInvoke(curry(f.bind(0, ...args))): f());

_
_const sum = (...values) => values.reduce((total, current) => total + current, 0)
curry(sum)(2)(2)(1) + 0 == 5 // true
_
1
user1034533

以下は、非単項パラメーターでも機能する、より一般的なソリューションです。

const sum = function (...args) {
  let total = args.reduce((acc, arg) => acc+arg, 0)
  function add (...args2) {
    if (args2.length) {
      total = args2.reduce((acc, arg) => acc+arg, total)
      return add
    }
    return total
  }

  return add
}

document.write( sum(1)(2)() , '<br/>') // with unary params
document.write( sum(1,2)() , '<br/>') // with binary params
document.write( sum(1)(2)(3)() , '<br/>') // with unary params
document.write( sum(1)(2,3)() , '<br/>') // with binary params
document.write( sum(1)(2)(3)(4)() , '<br/>') // with unary params
document.write( sum(1)(2,3,4)() , '<br/>') // with ternary params
0

新しいES6の方法で簡潔です。

呼び出しを終了して最終的な値を取得する場合は、最後にempty()を渡す必要があります。

const sum= x => y => !!y ? sum(x + y) : x;

このように呼び出します-

sum(10)(30)(45)();
0
Deepak K

以下の機能を利用できます

function add(num){
   add.sum || (add.sum = 0) // make sure add.sum exists if not assign it to 0
   add.sum += num; // increment it
   return add.toString = add.valueOf = function(){ 
      var rtn = add.sum; // we save the value
      return add.sum = 0, rtn // return it before we reset add.sum to 0
   }, add; // return the function
}

関数はオブジェクトであるため、プロパティを追加できます。これは、アクセスされたときにリセットされます。

0
Amit Joki

古い質問かもしれませんが、少し拡張された答え

function sum() {

    var args = [];
    args.Push(...arguments);

    function sumOfAllArguments() {
        return args.reduce((prev,items)=>prev + items, 0)
    }

    function v() {
        arguments && args.Push(...arguments);
        return arguments.length === 0 ? sumOfAllArguments() : v;
    }

    v.valueOf = v.toString = sumOfAllArguments;

    return v;

}
        
    

        console.log(sum(2)(2)(2)()) // 6
        console.log(sum(2)(2)(2).toString()) // 6
        console.log(sum(2)(2)(2).valueOf()) // 6
        console.log(+sum(2)(2)(2)) //6
        console.log(sum(2)(2)(2)) // f 6

        console.log(sum(2,2,2)(2,2)(2)) // f 12
        console.log(sum(2)(2,2)(2)()) //  8
0
shekhardtu

別の少し短いアプローチ:

 const sum = a => b => b? sum(a + b) : a;

使用可能:

console.log(
  sum(1)(2)(),
  sum(3)(4)(5)()
);
0
Jonas Wilms

sum(1)sum(1)(2)として呼び出し可能にするには、関数を返す必要があります。

関数は、呼び出すか、valueOfを使用して数値に変換できます。

function sum(a) {

   var sum = a;
   function f(b) {
       sum += b;
       return f;
    }
   f.toString = function() { return sum }
   return f
}
0
Vemba

これは、反復プロセスを使用した別の機能的な方法です

const sum = (num, acc = 0) => {
    if (!num) return acc;
    return x => sum(x, acc + num)
}

sum(1)(2)(3)()

そして一行

const sum = (num, acc = 0) => !num ? acc : x => sum(x, acc + num)

sum(1)(2)(3)()