Какая-то сумбурная статья получилось. Видно, что у автора накипело :) Но в статье как-то очень мало описано о «надеждах и разочарованиях» ООП, ожидал увидеть больше конкретики, а не то, что термины употребляются не правильно.
Если автор предлагает использовать в качестве классов теорию множеств, то спешу его предупредить, что она довольно ограничена Парадокс Рассела и попытки решить ее привели к созданию теории категорий.
Поэтому в ООП нет даже простейших операций над классами (сложение и вычитание множеств)
Эту задачу в терминах ООП можно решить при помощи костылей, но если хочется красивого решения, то почитайте про ADT. Они позволяют то, что вы хотите: создавать типы из других типов используя операции логического сложения и произведения. О том как это реазиловать в ООП можно почитать тут
Имхо надо начинать с декомпозиции, затем параллельно вводить понятие алгоритмической сложности, чтобы показать что декомпозиция может быть как эффективной так и нет. Затем можно рассмотреть структуры данных и абстракции. Язык в данном случае особой роли не играет. Не надо изобретать велосипед, за нас уже все написали. «Структура и интерпретация программ» — вот с чего надо начинать обучение программированию.
Нет, не так. В вашем случае bind вернет функцию, которая при вызове выдаст обычное число, а не пару [значение, новое сотояние]. Т.е. функция bind не возвратит монаду, а должна.
Попробую проиллюстрировать на примере javascript, как можно сохраняя чистоту «изменять» состояние, изобразив нечто схожее с монадами
Скрытый текст
//чистая функция
function random(state) {
//[значение, новое состояние]
return [state % 10, state + 1];
}
//обычная функция
function add4(v) {
return v + 4;
}
//fs - чистая функция наподобии random, state - начальное состояние
function makeMonad(fs, state) {
//функция не принимающая состояние, помещенная в "коробку"
return function () {
return fs(state);
};
}
//fs - функция наподобии random, f - обычная функция не принимающая состояние, наподобие add4
//возвращается функция, обернутая в монаду c другим состоянием.
function bind(fs, f) {
return function() {
var [value, state] = fs();
return [f(value), state];
};
}
//получить чистое значение из монады, без изменения состояния
function call(fs) {
return fs[0];
}
//тогда пример работы с генератором:
var generator = makeMonad(random, 0);
bind(generator, function(randomValue) {
//здесь работаем с псевдослучайным значением
});
На самом деле состояние не изменяется, а создается новое :)
Внутри монады State, когда вы выполняете bind с другой чистой функцией(вне монады State) у вас создается новое окружение с уже новым значением State. Это чем-то напоминает как работает scope в Javascript. Scope в данном случае выступает в качестве State и мы не меняем scope у исходной функции, а создаем новую функцию с новым измененным scope.
Спасибо за перевод. Надеюсь вы не остановитесь и продолжите перевод дальнейших статей.
Хотел уточнить вопрос насчет bottom, может кто-нибудь прояснит.
Как я понял, для того чтобы иметь возможность оперировать функциями, которые никогда не завершаться, как с математическими функциями мы расширяем множество типов значением bottom.
Значит ли это, что Bool = True | False на самом деле Bool = True | False | _|_?
И то, что () = _|_, т.е. у нас не существует типа, не содержащего ни одного элемента, т.к. любое множество типов должно содержать bottom?
Как мне кажется автор имел ввиду то, что для борьбы со сложностью мы пытаемся построить нашу программу опираясь на доменную область.
Но use case из доменной области могут быть очень не логичными, хаотичными (особенно для не посвященных). Отсюда следует вывод, что длина метода (предполагаем, что метод выполняет какой-то use case, зависит от сложности самого этого use case (т.е. составных его шагов)) на которые ограничения накладываются самой бизнес логикой а не программистами.
Не понятно, как новая иерархия может изменить структуру use case. Возможно есть способ строить более высокие абстракции поверх доменной модели, но это на мой взгляд только усложнит понимание программы
Основной целью статьи было заинтересовать людей функциональным программированием.
Насчет применения линз в Javascript: я не уверен на 100%, но возможно им найдется место в React.js. Насколько я знаю там нашли применение неизменяемые структуры данных. Могу ошибаться, т.к. знаком с ним только поверхностно.
Если автор предлагает использовать в качестве классов теорию множеств, то спешу его предупредить, что она довольно ограничена Парадокс Рассела и попытки решить ее привели к созданию теории категорий.
Эту задачу в терминах ООП можно решить при помощи костылей, но если хочется красивого решения, то почитайте про ADT. Они позволяют то, что вы хотите: создавать типы из других типов используя операции логического сложения и произведения. О том как это реазиловать в ООП можно почитать тут
Внутри монады State, когда вы выполняете bind с другой чистой функцией(вне монады State) у вас создается новое окружение с уже новым значением State. Это чем-то напоминает как работает scope в Javascript. Scope в данном случае выступает в качестве State и мы не меняем scope у исходной функции, а создаем новую функцию с новым измененным scope.
Надеюсь хоть немного стало понятнее )
Хотел уточнить вопрос насчет bottom, может кто-нибудь прояснит.
Как я понял, для того чтобы иметь возможность оперировать функциями, которые никогда не завершаться, как с математическими функциями мы расширяем множество типов значением bottom.
Значит ли это, что Bool = True | False на самом деле Bool = True | False | _|_?
И то, что () = _|_, т.е. у нас не существует типа, не содержащего ни одного элемента, т.к. любое множество типов должно содержать bottom?
Но use case из доменной области могут быть очень не логичными, хаотичными (особенно для не посвященных). Отсюда следует вывод, что длина метода (предполагаем, что метод выполняет какой-то use case, зависит от сложности самого этого use case (т.е. составных его шагов)) на которые ограничения накладываются самой бизнес логикой а не программистами.
Не понятно, как новая иерархия может изменить структуру use case. Возможно есть способ строить более высокие абстракции поверх доменной модели, но это на мой взгляд только усложнит понимание программы
Насчет применения линз в Javascript: я не уверен на 100%, но возможно им найдется место в React.js. Насколько я знаю там нашли применение неизменяемые структуры данных. Могу ошибаться, т.к. знаком с ним только поверхностно.