Когда я прочитал о концепции лифта, она реализована так (на Javascript)
const liftA2 = f => (a, b) => b.ap(a.map(f));
Я понимаю, что есть случай, когда liftA2
вызовет ошибку: когда b
— это Right
/Just
, а a
— это Left
/Nothing
, потому что сопоставление Left
/Nothing
ничего не сделает со значением, когда нам нужно, чтобы оно стало частично прикладная функция.
Когда a
и b
оба являются Left
, это не взрывается, но, конечно, значение возвращаемого Left
будет значением b
, что, я полагаю, может быть проблемой в зависимости от того, что вы ожидаете.
Стоит ли поднимать функцию для использования с этими типами? Должен ли я систематически защищаться от таких случаев перед использованием такой функции? Является ли приведенная выше реализация правильной/полной?
Подробнее о проблеме вы найдете ниже
Let us define the function to liftconst add = a => b => a + b;
В случае базового
Wrapper
, реализующегоof
,ap
иmap
, мы можем следить за тем, что происходитclass Wrapper { constructor(value) { this.value = value; } static of(value) { return new Wrapper(value); } map(f) { return Wrapper.of(f(this.value)); } ap(a) { return this.map(a.value); } } const a = Wrapper.of(1); const b = Wrapper.of(2); // liftA2 const tmp = a.map(add); // Wrapper { λ } b.ap(tmp); // Wrapper { 3 }
Но проблема с
Either
илиMaybe
в том, что у них есть случайLeft
/Nothing
, гдеmap
иap
предназначены для того, чтобы не делать ничего особенного.class Left { constructor(value) { this.value = value; } static of(value) { return new Left(value); } map(f) { return this; } ap(a) { return this; } } class Right{ constructor(value) { this.value = value; } static of(value) { return new Right(value); } map(f) { return Right.of(f(this.value)); } ap(a) { return this.map(a.value); } } const a = Left.of(1); const b = Right.of(2); // liftA2 const tmp = a.map(add); // Left { 1 } b.ap(tmp); // Error because tmp's value is not a function
Left
/Nothing
, которое было передано дляa
илиb
, или вы имеете в виду, что он генерирует исключение ( взорвется) и программа не работает что ли? - person Bergi   schedule 26.07.2020a
, когда обаLeft
? Это зависит от реализацииap
и должно быть задокументировано там. Вы все еще можете перевернуть свою функцию, чтобы поменять местами результаты. - person Bergi   schedule 26.07.2020ap
не ожидает частично примененной функции. Он ожидает частично примененную функцию в контексте. СMaybe
контекст представляет собой вычисление, которое может не дать результата. Не толькоa
/b
может бытьNothing
, но и результатомmap
. - person Iven Marquardt   schedule 26.07.2020value
, я имею в виду значение внутри контекста:this.value
в реализации, которую я только что добавил. - person geoffrey   schedule 26.07.2020Right.prototype.ap
не работает. Ему нужно различать аргументa
наLeft
иRight
, он не может просто получить доступ к своему.value
. - person Bergi   schedule 26.07.2020b
являетсяRight
, аa
-Left
. Что касается случая, когдаa
иb
оба являютсяLeft
, эта проблема не так велика, как первая, которую я выразил, и я не могу указать пальцем на то, что было бы проблематичным именно с этим результатом, кроме потери контекста, который произвел первыйLeft
(а). Я чувствую, что, вообще говоря, еслиLeft
является ошибкой или чем-то еще, вы, вероятно, захотите проверить, можно ли ее восстановить, прежде чем игнорировать ее, или вы можете что-то сделать с ошибкой, чтобы приготовить сообщение об ошибке или зарегистрировать его где-нибудь. - person geoffrey   schedule 26.07.2020ap
должен делать в этом случае? должен лиRight.ap
возвращатьLeft
, если аргументa
являетсяLeft
? Должен ли вообщеRight
знать о типеLeft
? У меня такое ощущение, что это несовместимо (по крайней мере, эстетически) с этой двуглавой реализацией. - person geoffrey   schedule 26.07.2020Right
ожидаемого типа вывода, поскольку нет значения для его создания, поэтому он должен вернуть значениеLeft
. В данном конкретном случае это в основном определяется интерфейсом монады. - person Bergi   schedule 26.07.2020Either
. Да, любой методEither
должен знать какLeft
, так иRight
. Ваша реализация с двумяclass
es немного странная в этом отношении. Конечно, вы можете эмулировать сопоставление с образцом с помощью динамической диспетчеризации, ноap
нужно сделать это дважды. - person Bergi   schedule 26.07.2020Either<string, number[]>
, с конструкторами типов, такими какEither<A, B>
, с конструкторами значений, такими какLeft
/Right
. Это может быть довольно запутанным! Последние создают значения, помеченные тегами, чтобы среда выполнения могла их различать. Теги не являются частью уровня типа, но являются частью уровня значения. - person Iven Marquardt   schedule 26.07.2020