开发者

How to transform this simple OOP program to a functional-programming language?

开发者 https://www.devze.com 2023-01-19 22:50 出处:网络
During the last months I have tried to code using the functional programming paradigm. Now I have a solution in OOP and I am trying to find a functional solution.

During the last months I have tried to code using the functional programming paradigm. Now I have a solution in OOP and I am trying to find a functional solution.

The problem is simple. I have an algorithm, which produces two different arrays as result (a and b). Now, I want to check how good the results are. Therefore I write several evaluation criteria for them. I hope pseudo-java source code is okay for you!

// first the Algorithm class
class Algorithm {
    private []a;
    private []b;

    Algorithm(input) {
        computeResult();
    }

    getA(){return a;}
    getB(){return b;}

    void computeResult() { 
        ... 
        ... // time-consuming operations 
        ... // set values for a and b
        ...
    }
}

// this class tests the Algorithm using a list of evaluation criteria
class AlgorithmTest {

    AlgorithmTest() {
        ... 
        ... // Definition of input
        ... // Definition of list of evaluation criteria evals
        ...
        Algorithm algorithm = new Algorithm(input); // Compute the result

        for (EvaluationCriterion eval : evals) {
            System.out.println(eval.getClassSimpleName()); // Print name of class
            System.out.println(eval.evaluate(algorithm));  // Print evaluation result
        }
    }
开发者_如何学JAVA
    main () {
        new AlgorithmTest();
    }
}

interface EvaluationCriterion {
    double evaluate(Algorithm a);
}

// an example implementation of a criterion
class EvaluationA implements EvalutationCriterion{
    double evaluation(Algorithm algorithm) {
        a = algorithm.getA();
        b = algorithm.getB();
        double c = anotherComputation(a, b);
        return c;
    }

    double anotherComputation(a, result){
        ... // compute and return result
    }
}

Is it possible to "transform" this source code using functional programming paradigm? I am sure it it, but can you still add new evaluation criteria easily like in the OOP approach?

I could write a module called algorithm that includes pure functions that compute either a or b. In this case I have to compute it twice, which requires to much time.

But how to do the evaluation step using multiple evaluation functions?


But how to do the evaluation step using multiple evaluation functions?

You'd pass in the functions you want to use, as first-class values.

Your type EvaluationCriterion is basically just the function type Algorithm -> Double (in Haskell syntax). EvaluationA, EvaluationB, etc. don't need to be new types. They're just values of type EvaluationCriterion. You can pass them as values, build a list of type [EvaluationCriterion], etc.

The irony here is that you've already used first-class functions in your solution. This abstraction-weak OOP language lacks first-class functions, so you had to apply a standardized workaround ("design pattern"). Converting it to a functional language (or just a reasonable OOP language) is a matter of removing complexity.

Now, as to how to eliminate the statefulness of Algorithm, I haven't thought about that. But do remember that FP does not mean "no state ever". Caching pure function results is quite a common thing to do.


Something like this:

type Algorithm = Input -> (A,B)

type Accuracy  = Double
type EvaluationCriterion = Algorithm -> Accuracy

example :: EvaluationCriterion
example f = size a / (size a + size b)
    where
    (a,b) = f 42

This particular example criterion is random nonsense, of course; you have to supply suitable functionality and types Input, A, B.


I think your Algorithm-class could be simply reduced to (Scala pseudocode - I think this is easier to understand than Haskell or Clojure as it is closer to Java)

def computeResult(input: Input): (List[Result1], List[Result2]) = ...

where (a,b) is a Tuple, a simple wrapper around two values a and b.

EvaluationCriterion could be

trait EvaluationCriterion {
   def evaluate(algo : Input => (List[Result1], List[Result2])): Double
}

If you have a Sequence (e.g. a List) of these criterias, you can write

evaluationCriterias.map(crit => (crit.getClass.toString, crit.evaluate(computeResult _)))

which would result in something like Seq((CritClass1, 1.2), (CritClass2, 0.99), (CritClass3, 0.54))


Since you mentioned Clojure, here's an easy way to do it:

(def algorithm-1 
  {:a some-calculate-a-for-algorithm-1
   :b some-calculate-b-for-algorithm-2})

(defn evaluation-1 [algorithm input]
  (some-computation-1 ((:a algorithm) input) ((:b algorithm) input)))

Basically you define your algorithms as being a map containing two functions (labelled :a and :b), you could easily add other data or functions into the algorithms if desired.

Then the evaluation functions just execute a computation on the results of calling the two functions for a given algorithm on the input.

If you want to get really clever, then you can create a macro as follows:

(defmacro build-evaluation-function [computation]
  `(fn [algorithm# input#] (~computation ((:a algorithm#) input#) ((:b algorithm#) input#))))

And then you can build as many evaluation functions as you like, using any function that takes two parameters as the computation:

(def evaluation-2 (build-evaluation-function add))

(def evaluation-3 (build-evaluation-function str))

; etc....
0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号