Ну для этого как минимум операции должны быть атомарными, а скорость роста всех возможных перестановок явно отобьет охоту проверять все возможные ситуации :)
Я не говорю еще про инвалидацию кэша процессоров, оптимизации компиляторов и пр.низкоуровневые вещи, меняющие выполнение операций.
Я думаю это попытка воплотить typeclass из Haskell.
Самый простой пример:
interface Eq {
bool Equal(a, b) { return !NotEqual(a, b);}
bool NotEqual(a, b) {return !Equal(a, b);}
}
Таким образом для реализации интерфейсов у нас минимальный набор операций для реализации это или Equal или NotEqual. В нек-ых случаях может оказаться, что операцию NotEqual реализовать проще чем Equal, а оставшуюся операцию мы получаем «бесплатно».
Вы заявили то, что ООП поощряет чистоту, а не то что позволяет писать методы, к-ые не используют состояние.
Не нужно ходить далеко, проведите эксперимент. Попросите ваших знакомых написать сложение двух чисел.
Могу поделиться своим результатом. В большинстве случаев решение будет выглядеть примерно так:
class Sum {
public int Value {get; private set;}
public Sum(int initial) {
Value = initial;
}
public void Add(int value) {
Value += value;
}
}
Рассмотрим такой простой кейс: нужно протестировать функцию к-ая валидирует некоторое значение и выдает список ошибок, если они есть.
Как протестировать ее используя ваш подход с учетом того, что сам порядок ошибок в списке не имеет значения?
Можно поинтересоваться почему в ФП не может быть const и let?
Const в них используются неявно, а let есть ничто иное как псевдоним, для некоторого выражения, наподобии того как в математики вводят дополнительные переменные
Да я ничего и не имею против for :)
На самом деле он вполне себе декларативен и если присмотреться то можно в нем увидеть монвду list в do нотации (особенно в for of)
Смысл map в том что производится трансформация над каждым элементом (можете считать что это групповая операция) и кол-во элементов на входе и на выходе обязано быть одинаковым
А я вот противоположной точки зрения
Глядя на композицию map, filter, reduce можно сразу выделить структуру даже не вникая в детали (банально если заканчивается reduce — значит результат одиночное значение, иначе — массив). С циклом же нужно полностью изучить весь код, чтобы выявить какую-то структуру.
Конечно понимаю. Я ведь даже писал, что нам на самом деле нет смысла использовать иммутабельные данные внутри reduce.
Вообще говоря это обычная практика когда надо произвести много операций над иммутабельным объектом, то заменять его на мутабельный, производить операции, а затем если нужно делать опять иммутабельным.
Тот же StringBuilder из C# примерно так и работает.
Если мы не используем всякие сторонние библиотеки для иммутабельных структур, то любой объект можно интерпретировать как мутабельный так и иммутабельный. И т.к. в случае reduce создается пустой объект — соответственно нет необходимости в преобразованиях вида
Иммутабельный->Мутабельный и Мутабельный->Иммутабельный
Код без Ramda — опять грязный, мутируете acc. Если мутируете, зачем тогда вообще reduce?
Да нет же. Object.assign — создает копию. А вообще на самом деле, т.к. js однопоточный и этот объект генерируется только внутри reduce можно было смела заменить на мутации. Получили бы выигрышь в производительности :)
Это чем лучше? Естественно писать a + b, а значит a.plus(b) — более естественный способ записи. А учитывая перегрузку операторов — он вообще сводится к a + b.
Раз Вы сами заговорили про перегрузку операторов, каким образом она реализуется?
...
public static ComplexNumber operator+(ComplexNumber a, ComplexNumber b)
{
return new ComplexNumber(a.real + b.real, a.imaginary + b.imaginary);
}
...
Ничего не напоминает статический метод? Да ведь это обычная функция :) Просто ее нужно ведь куда-то поместить… Статический метод, кстати это маркер того, что на самом деле нам нужна функция, а не метод.
На самом деле все просто — если мы пишем a.plus(b) — мы делегируем ответственность за операцию классу a. А чем он лучше чем класс b? (Конечно имеется ввиду что а и b разного типа).
Я не говорю еще про инвалидацию кэша процессоров, оптимизации компиляторов и пр.низкоуровневые вещи, меняющие выполнение операций.
Да, жизнь боль :(
Как раз-таки в этом и вся соль, что можно переопределить метод по умолчанию.
Самый простой пример:
Таким образом для реализации интерфейсов у нас минимальный набор операций для реализации это или Equal или NotEqual. В нек-ых случаях может оказаться, что операцию NotEqual реализовать проще чем Equal, а оставшуюся операцию мы получаем «бесплатно».
Не нужно ходить далеко, проведите эксперимент. Попросите ваших знакомых написать сложение двух чисел.
Могу поделиться своим результатом. В большинстве случаев решение будет выглядеть примерно так:
Рассмотрим такой простой кейс: нужно протестировать функцию к-ая валидирует некоторое значение и выдает список ошибок, если они есть.
Как протестировать ее используя ваш подход с учетом того, что сам порядок ошибок в списке не имеет значения?
Можно поинтересоваться почему в ФП не может быть const и let?
Const в них используются неявно, а let есть ничто иное как псевдоним, для некоторого выражения, наподобии того как в математики вводят дополнительные переменные
Да я ничего и не имею против for :)
На самом деле он вполне себе декларативен и если присмотреться то можно в нем увидеть монвду list в do нотации (особенно в for of)
Смысл map в том что производится трансформация над каждым элементом (можете считать что это групповая операция) и кол-во элементов на входе и на выходе обязано быть одинаковым
А я вот противоположной точки зрения
Глядя на композицию map, filter, reduce можно сразу выделить структуру даже не вникая в детали (банально если заканчивается reduce — значит результат одиночное значение, иначе — массив). С циклом же нужно полностью изучить весь код, чтобы выявить какую-то структуру.
Вообще говоря это обычная практика когда надо произвести много операций над иммутабельным объектом, то заменять его на мутабельный, производить операции, а затем если нужно делать опять иммутабельным.
Тот же StringBuilder из C# примерно так и работает.
Если мы не используем всякие сторонние библиотеки для иммутабельных структур, то любой объект можно интерпретировать как мутабельный так и иммутабельный. И т.к. в случае reduce создается пустой объект — соответственно нет необходимости в преобразованиях вида
Иммутабельный->Мутабельный и Мутабельный->Иммутабельный
Вот так надо было
Да нет же. Object.assign — создает копию. А вообще на самом деле, т.к. js однопоточный и этот объект генерируется только внутри reduce можно было смела заменить на мутации. Получили бы выигрышь в производительности :)
Собственно решение занимает по факту 1 строчку:
Ниже привел захардкоженные данные, чтобы можно было поиграться
Покажите теперь пожалуйста, как вы реализовываете это на ООП.
Раз Вы сами заговорили про перегрузку операторов, каким образом она реализуется?
Ничего не напоминает статический метод? Да ведь это обычная функция :) Просто ее нужно ведь куда-то поместить… Статический метод, кстати это маркер того, что на самом деле нам нужна функция, а не метод.
На самом деле все просто — если мы пишем a.plus(b) — мы делегируем ответственность за операцию классу a. А чем он лучше чем класс b? (Конечно имеется ввиду что а и b разного типа).
В случае plus(a, b) типы a,b равноценны.
Если хотите на родных map, filter, reduce, можно что-то вроде
Функция group пишется один раз, и может быть использована в других местах.
В случае ap в контейнере находится не значение, а функция. Т.е. this.__value — это функция поднятая на уровень контейнера.
Согласен с Вами. Как уже упоминал выше, если есть желание действительно разобраться почитайте это.
А состояние всей системы? :)