高次関数学習(JavaScript)
4033 ワード
この名前に惑わされないでください.私はjavascriptの高次関数の概念を話しています.本教程は高次教程ではありません.最近SICPを研究して、その中の高次関数の抽象に対していくつか体得があって、そしてjavascriptの中でいくつか実験を行って、今これらの実験を分析して、みんなに対してある程度助けがあることを望みます.高次関数思想は昔から計算可能理論の初期に遡ります.ラボラダ演算理論にはこの思想があります.最初の実現はlisp言語と言えるかもしれません.この演算モデルは図霊機の計算能力に相当すると言える.ただその後の歴史は馮諾依曼システムを選択しました.lambadaは仮想の実現として、同じ計算能力を持つ図霊機に運行するしかないです.より高いレベルの抽象的な抽象的なレベルは、例えば、小さな演算を一つの関数にパッケージ化することは抽象的であり、この抽象的な基礎の上で、もう一回抽象的にすることは高次の抽象である.lispなどの関数プログラミング言語ではこの概念が基本的です.その他の命令式プログラミング言語では、C、javaなど、テンプレートまたはインターフェースという概念が提供されている.
たとえば、私達は毎回1つの数の立方数を計算する必要があります.x*xの形を書く必要があります.もし1つの演算の中に立方のこのような演算を使うところがたくさんあると、符号化が面倒くさいかもしれません.コードもはっきりしないので、立方の運算を一つの関数に抽象化して、この関数を入力して、この入力の立方数に戻ります.たとえば:
このように、我々は「立方」を計算するための独立したモジュールを持っています.そして、言語の原生文を拡張することによって、「立方」という概念を表現することができます.このような抽象は分かりやすいです.C、javaなどの言語もこのような抽象を提供します.次にもう一つの例を見ます.まず関数を作成します.この関数の機能は以下の通りです.入力範囲[a,b] は、この範囲の数の合計として出力される. 入力[1,100]のように、出力5050.この関数は再帰的な形で比較的容易に実現される.
もちろん内部関数incは、identityがあまりにも簡単で、全く無視できますが、後に使うことを考えて、先にこのような形にします.この関数はよく働くことができますが、項目が大きくなるにつれて、ある範囲の数の立方晶和を計算するためにもう一つの関数が必要です.入力範囲[a,b] は、この範囲の数の立方と として出力される.
入力した[1,4]のように、出力100:1^3+2^3+3+4+3=1+8+27+64=100の場合、同じ再帰でこの関数を実現できます.
プロジェクトがさらに成長するにつれて、私達は今第三の関数を実現して、このような数列を求めて入力します.同じ[a,b]の範囲で、1/x*(x+2)を計算します.歩幅は4です.この数列の前n項と性質があります.無限のpi/8に近いこの数列はもちろん有用です.たとえば、Pi値を計算します.この値に8をかけると、piが近似的に計算されます.
mathematicaで計算してみましたが、この求和は確かにPI/8に限界があります.再帰でこの関数を実現できます.
この3つの関数を比較してみましょう.すぐにこの3つの関数は似ています.比較範囲の下付きスケーリングは、a>bなら0に戻り、そうでなければ2 に進む.はaの値を変更し、aを一定の演算を行い、自身 を再帰的に呼び出します.
以下のような疑似コード形式で作成できます.
このうち、funcNameは関数名で、nextは次のaを取る値(ステップサイズによるステップ)で、funcはaを計算します.私たちはこのコードをJavascriptコードに翻訳しやすいです.
この時、sumという関数に二つの追加のパラメータtermとnextを渡すと、私たちは希望の結果を得ることができます.今、私たちの求和関数はこのような形で書くことができます.
同様に、立方和の関数はこう書くことができる.
最後の一つ
sumに本物の計算演算子と計算ステップの演算子を渡すだけでいいです.簡単なテスト関数を与えます.
両方の運転結果は以下の通りです.
書き記す
js>
sumTester()
5050
100
3.141392653591793
ちなみに、これらの例はいずれもrhinoでテストしていますが、ブラウザでテストしたことがありません.最後のテスト関数のprintのように、ブラウザに埋め込まれているjsエンジンは正確に解析できないと推定されています.rhinoについてですが、javaeyに関連する文章がありますので、探してみてください.高次関数を使って,第一次抽象に基づいてもう一度抽象化し,関数の生成器を生成し,一定の演算子に伝達して,それぞれの類似の計算を完成させることができる.
たとえば、私達は毎回1つの数の立方数を計算する必要があります.x*xの形を書く必要があります.もし1つの演算の中に立方のこのような演算を使うところがたくさんあると、符号化が面倒くさいかもしれません.コードもはっきりしないので、立方の運算を一つの関数に抽象化して、この関数を入力して、この入力の立方数に戻ります.たとえば:
function cube(x){return x*x*x;}
このように、我々は「立方」を計算するための独立したモジュールを持っています.そして、言語の原生文を拡張することによって、「立方」という概念を表現することができます.このような抽象は分かりやすいです.C、javaなどの言語もこのような抽象を提供します.次にもう一つの例を見ます.まず関数を作成します.この関数の機能は以下の通りです.
function intSum(a, b){
function inc(x){ return x + 1; }
function identity(x){ return x; }
if(a > b){
return 0;
}else{
return intSum( inc(a) , b) + identity(a);
}
}
もちろん内部関数incは、identityがあまりにも簡単で、全く無視できますが、後に使うことを考えて、先にこのような形にします.この関数はよく働くことができますが、項目が大きくなるにつれて、ある範囲の数の立方晶和を計算するためにもう一つの関数が必要です.
入力した[1,4]のように、出力100:1^3+2^3+3+4+3=1+8+27+64=100の場合、同じ再帰でこの関数を実現できます.
function cubeSum(a, b){
function inc(x){ return x + 1; }
function cube(x){ return x * x * x; }
if(a > b){
return 0;
}else{
return cubeSum( inc(a) , b) + cube(a);
}
}
プロジェクトがさらに成長するにつれて、私達は今第三の関数を実現して、このような数列を求めて入力します.同じ[a,b]の範囲で、1/x*(x+2)を計算します.歩幅は4です.この数列の前n項と性質があります.無限のpi/8に近いこの数列はもちろん有用です.たとえば、Pi値を計算します.この値に8をかけると、piが近似的に計算されます.
mathematicaで計算してみましたが、この求和は確かにPI/8に限界があります.再帰でこの関数を実現できます.
function piSum(a, b){
function piTerm(x){ return 1/((x+2)*x); }
function piNext(x){ return x+4; }
if(a > b){
return 0;
}else{
return piSum( piNext(a) , b) + piTerm(a);
}
}
この3つの関数を比較してみましょう.すぐにこの3つの関数は似ています.
以下のような疑似コード形式で作成できます.
function (a, b){
if(a > b){
return 0;
}else{
return ((a), b) + (a);
}
}
このうち、funcNameは関数名で、nextは次のaを取る値(ステップサイズによるステップ)で、funcはaを計算します.私たちはこのコードをJavascriptコードに翻訳しやすいです.
function sum(term, a, next, b){
if(a > b){
return 0;
}else{
return sum(term, next(a), next, b) + term(a);
}
}
この時、sumという関数に二つの追加のパラメータtermとnextを渡すと、私たちは希望の結果を得ることができます.今、私たちの求和関数はこのような形で書くことができます.
function intSum(a, b){
function inc(x){return x + 1;}
function identity(x){return x;}
return sum(identity, a, inc, b);
}
同様に、立方和の関数はこう書くことができる.
function cubeSum(a, b){
function inc(x){return x + 1;}
function cube(x){return x * x * x;}
return sum(cube, a, inc, b);
}
最後の一つ
function piSum(a, b){
function piTerm(x){ return 1/((x+2)*x); }
function piNext(x){ return x+4; }
return sum(piTerm, a, piNext, b);
}
sumに本物の計算演算子と計算ステップの演算子を渡すだけでいいです.簡単なテスト関数を与えます.
function sumTester(){
print(intSum(1, 100)); // should print 5050
print(cubeSum(1, 4)); // should print 100
print(piSum(1, 10000)*8); // should print PI
}
両方の運転結果は以下の通りです.
書き記す
js>
sumTester()
5050
100
3.141392653591793
ちなみに、これらの例はいずれもrhinoでテストしていますが、ブラウザでテストしたことがありません.最後のテスト関数のprintのように、ブラウザに埋め込まれているjsエンジンは正確に解析できないと推定されています.rhinoについてですが、javaeyに関連する文章がありますので、探してみてください.高次関数を使って,第一次抽象に基づいてもう一度抽象化し,関数の生成器を生成し,一定の演算子に伝達して,それぞれの類似の計算を完成させることができる.