19
15

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

JavaScript:関数を合成する関数

Last updated at Posted at 2018-07-19

前にもやりましたが、今回は違うアプローチで任意の数の関数を合成する関数composeを作ってみます。

二つの関数を合成する

まんまですが:

const compose2 = (f2, f1) => x => f2( f1( x ) );

二個の関数 f2, f1 と x を引数にとって、xにf1を適用してその結果にf2を適用する、ってことです。

三つの関数を合成する

これもまんまです。

const compose3 = (f3, f2, f1) => x => f3( f2( f1( x ) ) );

3個の関数 f3, f2, f1 と x を引数にとって、xにf1を適用してその結果にf2を適用してその結果にf3を適用する、ってことです。

n個の関数を合成する

類推すればこんなイメージになると思います。ちゃんとしたコードじゃないですが。

const composeN = (fn, ... ,f2,f1) => x => fn( ... f2( f1( x ) ) ... ); 

n個の関数 fn, ... , f2, f1 と x を引数にとって、xにf1を適用してその結果にf2を適用して...という風にfnまで順に関数を適用していく、ってことです。

これで何個の関数を合成する関数でも書けるようになりました。
compose5 でも compose100 でも自由自在です。
え?そんな関数、書きたくない? 長ったらしいわりに使い回しが効かず全然便利じゃない? そうですよね....

#任意の個数の関数を合成するには?
簡単です。残余引数とreduceRightを使えばよい。

残余引数rest parameters

引数を ( ...fs ) と書くと、関数定義内で引数を fs という名前の配列として扱えます。"..."は何かの省略のてんてんではなく、れっきとした構文要素です。

const compose = ( ...fs ) => x =>(配列fsとxを使ったなにかの処理)

みたいな感じで書けます。

reduceRight

残余引数を使って引数が配列で扱えるようになったので、配列のメソッドがそのまま使えます。
reduceRightはreduceの右から版です。配列の最後の方から適用されていきます。あとはreduceと同じ。
この場合は、初期値 x に配列の要素(=関数)を適用しその結果にまた次の要素を適用していくので、アキュムレータをacc、配列 fs の要素を f として、コールバック関数を(acc, f) => f(acc)としとけば良い。

fs.reduceRight( (acc, f) => f(acc), x )

まとめると...

const compose = ( ...fs ) => x => fs.reduceRight( ( acc, f ) => f( acc ) , x );

できたー。

ちなみに:他のやりかただと...

//再帰:
const composeR = (...fs) => x =>
  fs.length === 0 ? x
  : composeR( ...fs.slice( 0, -1 ) )( fs[ fs.length - 1 ]( x ) )
;

//for loop:
const composeFor = (...fs) => x => {
  let acc = x;
  for(let i = fs.length-1; i >= 0; i--) acc = fs[i](acc);
  return acc;
};
19
15
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
19
15

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?