javascript関数式プログラミングの一例分析
10279 ワード
jsは他の動的言語のように高次関数を書くことができます.高次関数とは関数を操作できる関数です.jsの中で関数は徹底的に底の対象であるため、最初のクラスの公民に属しています.これは関数式プログラミングの先決条件を提供しています.下記には一例コードを提供します.js教程によると、配列要素の平均値と標準偏差を計算する機能があります.まず、関数ではないプログラムの書き方を列挙します.
map関数も簡単です.配列の各要素と同じように動作して、動作後の配列を返します.これはルビーコードの例です.jsコードはこれと類似しています.
var data = [1,1,3,5,5];
var total = 0;
for(var i = 0;i < data.length;i++)
total += data[i];
var mean = tatal/data.length; // 3
//
total = 0;
for(var i = 0;i < data.length;i++){
var deviation = data[i] - mean;
tatal += deviation * deviation;
}
var stddev = Math,.sqrt(total/(data.length-1));// 2
関数式プログラミングを使用するために、いくつかのヘルプ関数(helper functions)を事前に定義します.//
function array(a,n){
return Array.prototype.slice.call(a,n||0);
}
//
function partial_left(f){
var args = arguments;
return function(){
var a = array(args,1);
a = a.concat(array(arguments));
return f.apply(this,a);
};
}
//
function partial_right(f){
var args = arguments;
return function(){
var a = array(arguments);
a = a.concat(array(args,1));
return f.apply(this,a);
};
}
// , undefined 。
function partial(f){
var args = arguments;
return function(){
var a = array(args,1);
var i = 0,j = 0;
for(;i<a.length;i++)
if(a[i] === undefined)
a[i] = arguments[j++];
a = a.concat(array(arguments,j));
return f.apply(this,a);
};
}
// f(g())
function compose(f,g){
return function(){
return f.call(this,g.apply(this,arguments));
};
}
関数で完全にプログラムされたjsコードを以下に示します.var data = [1,1,3,5,5];
var sum = function(x,y){return x+y;};
var product = function(x,y){return x*y;};
var neg = partial(product,-1);
var square = partial(Math.pow,undefined,2);
var sqrt = partial(Math.pow,undefined,0.5);
var reciprocal = partial(Math.pow,undefined,-1);
// , :)
var mean = product(reduce(data,sum),reciprocal(data.length));
var stddev = sqrt(product(reduce(map(data,compose(square,partial(sum,neg(mean)))),sum),reciprocal(sum(data.length,-1))));
reduceとmap関数を除いて,他の関数の前面に提示した.reduce関数はrubyのinject関数と似ています.ary = (1..10).to_a
ary.inject(0) {|sum,i|sum + i} // 55
jsの書き方は以下の通りです.var ary = [1,2,3,4,5,6,7,8,9,10]
ary.reduce(function(sum,i){
return sum + i;
},0);
0はsumの初期値です.省略するとsumは配列の最初の要素の値です.ここでは省略できます.map関数も簡単です.配列の各要素と同じように動作して、動作後の配列を返します.これはルビーコードの例です.jsコードはこれと類似しています.
a = (1..3).to_a; # [1,2,3]
a.map {|x| x*2} # [2,4,6]
次に、その長い列のコードを分析します.sumとproductは要素加算と乗算の関数を定義しました.negも一つの関数機能であり、product(-1,x)であり、x値に負を求める.スクウェア関数は、Math.pow(x,2)、すなわちxの平方値を計算し、ここでのpartialの第二パラメータはundefinedであることに注意してください.これは、ここの形参が最初の実参加によってカバーされることを意味します.もう一つの明白点:スクウェア(x)機能はMath.pow(x,2)に等しい.sqrt関数はスクウェアと同様で、機能はMath.pow(x,0.5)に相当し、xを計算する二乗に相当する.最後の関数reciprocalも難しくないです.Math.pow(x,-1)、つまりxの負の方を計算します.xの逆数を計算するのに相当します.以下は、上の様々な関数を一緒にこねる方法です.)まず平均値の計算を見てください.簡単です.配列要素の和を先に計算して、配列長の逆数、つまり行列と行列長さを計算します.最後に難しそうな標準偏差を見たら、私達は内向的に外を見たほうがいいです.まずnegを含む層を見てください.// sum(-1 * mean + x)
partial(sum,neg(mean)
compose関数を見ます.// , :
//square(sum(-1*mean + x)), ( , , ...):
//Math.pow(sum(-1*mean + x),2);
compose(square,sum(-1*mean + x))
次にmap関数を見ます.// !? data x, , , data data , 2 。
map(data,Math.pow(sum(-1*mean + x),2))
続いてmapの外のreduce関数を見ます.// 。
reduce(map(...),sum)
そしてreciprocal関数を見てください.// (data.length-1)
reciprocal(sum(data.length,-1))
外層のproduct関数を見てください.// (data.length-1)
product(reduce(...),reciprocal(...))
最外層のsqrtは以上の除算法で得られた結果に対して平方根を求めると表しています.みんなは前の非関数プログラミングのコードを照らし合わせてみてもいいです.同じです.最後に視聴者の皆さんが「まだ読めていない」と言ったら、それは完全に猫の言語表現能力の問題です.質問を歓迎します.説明が終わったら、成果をあげる.