Чисто функциональное программирование

Итак, я опытный программист ООП (прежде всего С++), только сейчас начинаю окунаться в функциональное программирование. По моему мнению, в чисто функциональной парадигме функции не должны иметь условностей и должны быть разбиты как можно больше, используя currying. Может ли кто-нибудь предоставить мне "чистую" функциональную версию следующего примера? Предпочтительно использовать любую строгую технику, которая будет частью функциональной парадигмы:

let rec greatestCommonFactor a b =
    if a = 0 then b
    elif a < b then greatestCommonFactor a (b - a)
    else greatestCommonFactor (a - b) b

Ответы

Ответ 1

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

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

let add2 x = x + 2

Теперь, когда значение add2 2 появляется в нашей программе, мы можем заменить значение 4 без изменения поведения программы.

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

let add2Print x =
    printfn "%d" x
    x + 2

Хотя результат функции такой же, как и раньше, мы больше не можем выполнять подстановку значений со значением 4 без изменения поведения нашей программы, потому что наша функция имеет дополнительный побочный эффект печати на консоль.

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


let rec greatestCommonFactor a b =
    if a = 0 then b
    elif a < b then greatestCommonFactor a (b - a)
    else greatestCommonFactor (a - b) b

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

Чтобы быть ясным, нет абсолютно никакой проблемы с функциями, содержащими условные обозначения в функциональном программировании. Часто, однако, мы используем сопоставление шаблонов, а не выражения if/elif/else, но в примере, который вы описали, это чисто стилистический. Альтернативным выражением вашей функции с использованием сопоставления с образцом было бы следующее:

let rec greatestCommonFactor a b =
    match a with
    |0 -> b
    |a' when a' < b -> greatestCommonFactor a' (b - a')
    |a' -> greatestCommonFactor (a' - b) b