Статья, на которую вы ссылаетесь, основана на статье sigfpe, в которой используется перевернутое определение bind:
Во-первых, я перевернул определение bind
и написал его как слово 'bind', тогда как обычно оно пишется как оператор >>=
. Так что bind f x
обычно записывается как x >>= f
.
Итак, Haskell bind
принимает значение, заключенное в монаду, и возвращает функцию, которая принимает функцию, а затем вызывает ее с извлеченным значением. Возможно, я использую неточную терминологию, поэтому, может быть, лучше с кодом.
У вас есть:
sine x = (sin x, "sine was called.")
cube x = (x * x * x, "cube was called.")
Теперь, перевод вашего JS-связывания (Haskell выполняет автоматическое каррирование, поэтому вызов bind f
возвращает функцию, которая принимает кортеж, а затем сопоставление с образцом заботится о распаковке его в x
и s
, надеюсь, это понятно ):
bind f (x, s) = (y, s ++ t)
where (y, t) = f x
Вы можете видеть, как он работает:
*Main> :t sine
sine :: Floating t => t -> (t, [Char])
*Main> :t bind sine
bind sine :: Floating t1 => (t1, [Char]) -> (t1, [Char])
*Main> (bind sine . bind cube) (3, "")
(0.956375928404503,"cube was called.sine was called.")
Теперь давайте изменим аргументы bind
:
bind' (x, s) f = (y, s ++ t)
where (y, t) = f x
Вы можете ясно видеть, что он все еще делает то же самое, но с немного другим синтаксисом:
*Main> bind' (bind' (3, "") cube) sine
(0.956375928404503,"cube was called.sine was called.")
Теперь у Haskell есть синтаксическая хитрость, которая позволяет вам использовать любую функцию в качестве инфиксного оператора. Таким образом, вы можете написать:
*Main> (3, "") `bind'` cube `bind'` sine
(0.956375928404503,"cube was called.sine was called.")
Теперь переименуйте bind'
в >>=
((3, "") >>= cube >>= sine
), и вы получите то, что искали. Как видите, с помощью этого определения вы можете эффективно избавиться от отдельного оператора композиции.
Перевод новой вещи обратно в JavaScript привел бы к чему-то вроде этого (обратите внимание, что снова я только меняю порядок аргументов):
var bind = function(tuple) {
return function(f) {
var x = tuple[0],
s = tuple[1],
fx = f(x),
y = fx[0],
t = fx[1];
return [y, s + t];
};
};
// ugly, but it's JS, after all
var f = function(x) { return bind(bind(x)(cube))(sine); }
f([3, ""]); // [0.956375928404503, "cube was called.sine was called."]
Надеюсь, что это помогает, а не вводит больше путаницы - дело в том, что эти два определения связывания эквивалентны, различаются только синтаксисом вызова.