Как преобразовать эту простую программу ООП в язык функционального программирования? - PullRequest
2 голосов
/ 15 октября 2010

В последние месяцы я пытался кодировать, используя парадигму функционального программирования.Теперь у меня есть решение в ООП, и я пытаюсь найти функциональное решение.

Проблема проста.У меня есть алгоритм, который выдает два разных массива в качестве результата (a и b).Теперь я хочу проверить, насколько хороши результаты.Поэтому я пишу несколько критериев оценки для них.Я надеюсь, что исходный код псевдо-Java вам подходит!

// 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
        }
    }

    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
    }
}

Возможно ли "преобразовать" этот исходный код с помощью парадигмы функционального программирования?Я уверен, что это так, но вы все еще можете легко добавить новые критерии оценки, как в подходе ООП?

Я мог бы написать модуль под названием алгоритм, который включает в себя чистые функции, которые вычисляют либо a, либо b.В этом случае я должен вычислить его дважды, что требует много времени.

Но как сделать шаг оценки, используя несколько функций оценки?

Ответы [ 4 ]

11 голосов
/ 15 октября 2010

Но как выполнить шаг оценки с использованием нескольких функций оценки?

Вы передали бы функции, которые хотите использовать, в качестве первоклассных значений.

Ваш тип EvaluationCriterion в основном просто тип функции Algorithm -> Double (в синтаксисе Haskell).EvaluationA, EvaluationB и т. Д. Не должны быть новыми типами.Это просто значения типа EvaluationCriterion.Вы можете передавать их как значения, создавать список типа [EvaluationCriterion] и т. Д.

Ирония в том, что вы уже использовали первоклассные функции в своем решении.В этом языке ООП со слабой абстракцией отсутствуют первоклассные функции, поэтому вам пришлось применить стандартизированный обходной путь («шаблон проектирования»).Преобразование его в функциональный язык (или просто разумный язык ООП) - это вопрос устранения сложности.

Теперь, что касается того, как устранить состояние Algorithm, я не имеюЯ не думал об этом.Но помните, что FP не означает «никогда не бывает».Кэширование чистых результатов функций - обычное дело.

3 голосов
/ 15 октября 2010

Примерно так:

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

Этот конкретный примерный критерий, конечно, случайная чепуха;Вы должны предоставить подходящую функциональность и типы Input, A, B.

1 голос
/ 15 октября 2010

Поскольку вы упомянули Clojure, вот простой способ сделать это:

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

По сути, вы определяете свои алгоритмы как карту, содержащую две функции (помеченные: a и: b), при желании вы можете легко добавить другие данные или функции в алгоритмы.

Затем функции оценки просто выполняют вычисление по результатам вызова двух функций для данного алгоритма на входе.

Если вы хотите стать действительно умным, то вы можете создать макрос следующим образом:

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

И затем вы можете построить столько функций оценки, сколько захотите, используя любую функцию, которая принимает в качестве вычисления два параметра:

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

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

; etc....
1 голос
/ 15 октября 2010

Я думаю, что ваш Algorithm-класс можно просто уменьшить до (псевдокод Scala - я думаю, что это легче понять, чем Haskell или Clojure, поскольку он ближе к Java)

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

где (a, b) является Tuple, простой оберткой вокруг двух значений a и b.

EvaluationCriterion может быть

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

Если у вас есть последовательность (например, список) этих критериев, вы можете написать

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

, что приведет к чему-то вродеSeq((CritClass1, 1.2), (CritClass2, 0.99), (CritClass3, 0.54))

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...