您链接的文章基于 sigfpe 的文章,该文章使用了绑定的翻转定义:
第一件事是我颠倒了的定义bind
并将其写为“绑定”这个词,而它通常写为 operator >>=
。所以bind f x
通常写为x >>= f
。
因此,Haskellbind
接受一个包含在 monad 中的值,并返回一个函数,该函数接受一个函数,然后用提取的值调用它。我可能使用了不精确的术语,所以使用代码可能会更好。
你有:
sine x = (sin x, "sine was called.")
cube x = (x * x * x, "cube was called.")
现在,翻译你的 JS 绑定(Haskell 会自动进行柯里化,所以调用bind f
会返回一个带元组的函数,然后模式匹配负责将其解包到x
ands
中,我希望这是可以理解的):
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."]
希望这会有所帮助,而不是引入更多的混乱——关键是这两个绑定定义是等价的,只是调用语法不同。