In che modo le persone si liberano dei rami condizionali nella Programmazione funzionale?

8

Casi di switch di lunga durata o costrutti if-else-if sono evitati in OOP usando il polimorfismo ovunque sia applicabile.

invece di ramificarsi facendo corrispondere un valore, la ramificazione viene eseguita a livello di classe stessa.

In che modo un approccio simile può essere applicato nel paradigma della programmazione funzionale, in particolare Clojure?

    
posta Amogh Talpallikar 28.06.2013 - 08:39
fonte

3 risposte

13

Non li evitano, li abbracciano usando la sintassi della corrispondenza del modello.

Ma la programmazione funzionale è in gran parte ortogonale alla programmazione orientata agli oggetti, quindi la maggioranza assoluta dei linguaggi "funzionali" è anche orientata agli oggetti¹, incluso il clojure. In effetti, i multi-metodi di clojure sono persino migliori dei semplici metodi virtuali di Java, poiché possono inviare dinamicamente tipi di argomenti multipli, non solo il primo.

Esiste un linguaggio puramente funzionale che non ha un polimorfismo dinamico, Haskell. In Haskell è possibile definire multi-metodi tramite classi di tipi, ma i tipi sono risolti in fase di compilazione. Per avere tipi diversi in fase di esecuzione, devi creare un tipo di unione e devi scrivere la funzione con pattern match (che è come la catena if, ma con una sintassi più comoda) o chiedere al compilatore di derivare il metodo componendo il metodo metodi dei tipi costitutivi. Oppure usa l'estensioneforall di GHC%.

¹ Per object-oriented intendo che il linguaggio ha una qualche forma di polimorfismo dinamico con dispatch basato sul tipo di runtime effettivo. Molti nuovi linguaggi hanno solo il polimorfismo "basato sui tratti" in cui possono essere ereditate solo le interfacce; Lo considero come orientato agli oggetti e per lo scopo di questa risposta è sufficiente.

    
risposta data 28.06.2013 - 13:05
fonte
4

Questa è una domanda molto vecchia, ma mi sembra che mancassero le risposte.

Come hai detto, nella ramificazione OO viene spesso spostato a livello di classe. Pensiamo a cosa significa:

  1. Il metodo factory gestisce la ramificazione, restituendo una classe derivata.
  2. La classe derivata è una raccolta di metodi semplificati.
  3. Quindi il metodo factory è un metodo che restituisce metodi semplificati.

Questo è esattamente il modo in cui lo gestiresti: una funzione di ordine superiore. La tua funzione di ordine superiore gestisce la ramificazione, restituendo funzioni semplificate per il consumo.

Nel contesto della tua domanda, il polimorfismo è un po 'un'astrazione per questo - con una maggiore sicurezza del tipo.

    
risposta data 22.11.2017 - 05:41
fonte
-3

Nel linguaggio di programmazione funzionale, possiamo usare funzioni e parametri chiave per sbarazzarci dei rami condizionali. Questo uso medio funziona con condizioni param invece di "if esle". Vedi l'esempio 3. Come computeSphereArea ({radius: 25.55})

Esempio 1: OOP // in OOP (usa java ad esempio (sourceCode da: 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());
    }
}

Esempio 2: funzionale come oop. // in programmazione funzionale (usa javascript per esempio):

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());

// Anche se questo non è puro esempio di programma funzionale, ma con interfaccia funzionale, come initCircle () initSphere (). È possibile creare più funzioni come computeCircleArea () computeSphereArea () lo rende più funzionale. // PS: typeOf () è qui: link

Example3: Ok, rendiamolo più funzionale:

/** 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()");
    
risposta data 28.06.2013 - 12:36
fonte

Leggi altre domande sui tag