実行時間の長いswitchケースまたはif-else-if構文は、適用可能な場合はどこでも、ポリモーフィズムを使用してOOPで回避されます。
値を突き合わせて分岐する代わりに、分岐はクラスレベル自体で行われます。
関数型プログラミングのパラダイム、特にClojureで同様のアプローチをどのように適用できますか?
実行時間の長いswitchケースまたはif-else-if構文は、適用可能な場合はどこでも、ポリモーフィズムを使用してOOPで回避されます。
値を突き合わせて分岐する代わりに、分岐はクラスレベル自体で行われます。
関数型プログラミングのパラダイム、特にClojureで同様のアプローチをどのように適用できますか?
回答:
彼らはそれらを避けません、彼らはパターンマッチ構文を使用してそれらを受け入れます。
ただし、関数型プログラミングはオブジェクト指向プログラミングとほぼ直交しているため、「関数型」言語の絶対的な大多数も、clojureを含むオブジェクト指向です。実際、clojureのマルチメソッドは、最初の引数だけでなく、複数の引数の型に動的にディスパッチできるため、Javaの単純な仮想メソッドよりも優れています。
動的なポリモーフィズムを持たない純粋に関数型の言語であるHaskellがあります。Haskellでは、型クラスを介してマルチメソッドを定義できますが、型はコンパイル時に解決されます。実行時にさまざまな型を使用するには、共用体型を作成する必要があり、パターンマッチを使用して関数を作成する(ifチェーンに似ていますが、より便利な構文を使用する)か、または構成要素タイプのメソッド。または、GHC forall
拡張を使用します。
objectオブジェクト指向とは、言語に、実際の実行時の型に基づいてディスパッチする動的ポリモーフィズムの形式があることを意味します。多くの新しい言語は、「トレイトベース」のポリモーフィズムしか持たないため、インターフェースのみを継承できます。私はそれをオブジェクト指向であるとみなし、この答えの目的にはそれで十分です。
forall
拡張を使用しない限り、完全にコンパイル時です。
これは非常に古い質問ですが、答えが足りないような気がします。
あなたが述べたように、オブジェクト指向ではブランチはクラスレベルに頻繁に移されます。それが何を意味するのか考えてみましょう:
それがまさにあなたがそれを処理する方法です:高次関数。より高次の関数は分岐を処理し、効率化された関数を使用して返します。
あなたの質問の文脈では、ポリモーフィズムはそのためのちょっとした抽象化です-型安全性が追加されています。
関数型プログラミング言語では、関数とキーパラメータを使用して、条件付きブランチを取り除くことができます。つまり、「if esle」の代わりに、条件パラメーターを持つ関数を使用します。例3を参照してください。computeSphereArea({radius:25.55})として
例1:OOPで// OOPを使用(たとえば、javaを使用(sourceCode from:http://developer.51cto.com/art/200907/136506.htm)):
public abstract class Shape {
// ...
public abstract void computeArea();
public abstract void computeVolume();
public abstract double getArea();
public abstract double getVolume();
}
public class Circle extends CircleShape2 {
// ...
double volume = 0.0; //
public void computeArea() { //
area = Math.PI * radius * radius;
}
public double getArea() {
return area;
}
public void computeVolume() {} //
public double getVolume() {
return volume;
}
}
public class Sphere extends Circle {
// ...
public void computeArea() { //
super.computeArea(); //
area = 4 * area;
}
public void computeVolume() { //
super.computeArea(); //
volume = 4.0 / 3 * radius * area;
}
}
public class CircleShapeApp {
public static void main(String[] args) {
Circle circle = new Circle(12.98);
Sphere sphere = new Sphere(25.55);
Shape shape = circle; //
//
shape.computeArea();
shape.computeVolume();
System.out.println("circle area: " + shape.getArea());
System.out.println("circle volume: " + shape.getVolume());
//
shape = sphere;
shape.computeArea();
shape.computeVolume();
System.out.println("Sphere area: " + shape.getArea());
System.out.println("Sphere volume: " + shape.getVolume());
}
}
例2:oopのような機能。//関数型プログラミング(たとえば、JavaScriptを使用):
function initShape(v) {
var shape = {};
v = v || {};
if (typeOf(v, 'object') === true) {
shape.volumne = v.volumne || 0.0;
shape.computeArea = v.computeArea || function() {};
shape.computeVolume = v.computeVolume || function() {};
shape.getArea = v.getArea || function() {};
shape.getVolume = v.getVolume || function() {};
}
return shape;
}
function initCircle(v) {
var circle = {};
v = v || {};
if (typeOf(v, 'object') === true) {
circle.volume = 0.0;
circle.radius = v.radius || 0.0;
circle.computeArea = v.computeArea || function() {
this.area = Math.PI * this.radius * this.radius;
};
circle.computeVolume = function() {};
circle.getArea = v.getArea || function() {
return this.area
};
circle.getVolume = v.getVolume || function() {
return this.volume
};
}
return initShape(circle);
}
function initSphere(v) {
var sphere = {}
v = v || {};
if (typeOf(v, 'object') === true) {
var circle = initCircle(v);
sphere = circle;
sphere.volume = v.volume;
sphere.computeArea = function() {
circle.computeArea();
this.area = 4 * circle.area;
}
sphere.computeVolume = function() {
circle.computeArea();
this.volume = 4.0 / 3 * this.radius * circle.area;
}
}
return initShape(sphere);
}
var circle = initCircle(12.98);
circle.computeArea();
circle.computeVolume();
console.log("circle area: " + circle.getArea());
console.log("circle volume: " + circle.getVolume());
var sphere = initShpere(25.55);
sphere.computeArea();
sphere.computeVolume();
console.log("sphere area: " + sphere.getArea());
console.log("sphere volume: " + sphere.getVolume());
//ただし、これは純粋な関数型プログラムの例ではありませんが、initCircle()initSphere()のような関数型インターフェースを使用しています。// PS:typeOf()はこちら:https : //github.com/will-v-king/javascript-showMe
例3:OK、もっと機能的にしましょう:
/** in functional code shape became meaningless.
function initShape(v) {
var shape = {};
v = v || {};
if (typeOf(v, 'object') === true) {
shape = v.object || v.shape || shape;
shape.volumne = v.volumne || 0.0;
}
return shape;
}
function computeShapeArea(v){
}
function computeShapeVolume(v){
}
*/
function initCircle(v) {
var circle = {};
v = v || {};
if (typeOf(v, 'object') === true) {
circle = v.object || v.circle || circle;
circle.volume = 0.0;
circle.radius = v.radius || 0.0;
}
return initShape(circle);
}
function computeCircleArea(v){
var area;
v = v || {};
if(typeOf(v) === 'Object'){
var radius = v.radius || v.object.radius || v.circle.radius;
if(!typeOf(v,'undefined')){
area = Math.PI * radius * radius;
}
}
return area;
}
function computeCircleVolume(v){
return 0.0;
}
/**function initCircle and initSphere are not necessary. why? see the last line.*/
function initSphere(v) {
var sphere = {}
v = v || {};
if (typeOf(v, 'object') === true) {
var circle = initCircle(v);
sphere = circle;
sphere.volume = v.volume;
}
return initShape(sphere);
}
function computeSphereArea(v){
var area;
v = v || {};
if(typeOf(v) === 'Object'){
var radius = v.radius || v.object.radius || v.sphere.radius;
if(!typeOf(v,'undefined')){
area = 4 * computeCircleArea({radius:radius}); // **POINT** the same as :circle.computeArea(); this.area = 4 * circle.area;
}
}
return area;
}
function computeSphereVolume(v){
var volume;
v = v || {};
if(typeOf(v,'object') === ture){
radius = v.radius || typeOf(v.object, 'object') === true ? v.object.radius : typeOf(v.sphere, 'Object') === true ? v.sphere.radius : 0.0;
var circleArea = computeCircleArea({radius:radius});
if(typeOf(circleArea,'number')=== true){
volume = 4.0 / 3 * radius * computeCircleArea({radius:radius}); // **POINT** the same as: circle.computeArea(); this.volume = 4.0 / 3 * this.radius * circle.area;
}
}
return volume;
}
var circle = initCircle({radius:12.98});
console.log("circle area: " + computeCircleArea(circle) );
console.log("circle volume: " + computeCircleVolume(circle) );
var sphere = initShpere(25.55);
console.log("sphere area: " + computeSphereArea({radius:25.55}) );
console.log("sphere volume: " + computeSphereVolume({radius:25.55}) );
console.log("sphere object is unused.That means initSphere is also not necessary as initShape()");