Ross Paterson:箭头和计算介绍了trace
函数(第 11 页):
trace :: ((a, c) -> (b, c)) -> a -> b
trace f a = let (b, c) = f (a, c) in b
该trace
函数对于模块化循环程序中的魔术反馈步骤很有用。例如,考虑 Richard Bird 的著名repmin
函数,它找到一棵树的最小叶值并创建一棵相同的树,每个叶值都被最小叶值替换,这两者都是通过巧妙地使用惰性求值和局部递归(如提供letrec
):
data Tree = Leaf Int | Node Tree Tree deriving Show
repmin :: Tree -> Tree
repmin = trace repmin'
repmin' :: (Tree, Int) -> (Tree, Int)
-- put the minimum value m into the leaf and return the old value n as the minimum
repmin' (Leaf n, m) = (Leaf m, n)
-- copy the minimum value m into both the left and right subtrees and
-- set the minimum value m to the minimum of both the left and right subtrees
repmin' (Node l r, m) = let (l', lmin) = repmin' l m in
let (r', rmin) = repmin' r m in
(Node l' r', lmin `min` rmin)
无论如何,我想知道如何trace
在 JavaScript 中实现该函数,以便我们可以实现repmin
如下:
function Leaf(value) {
this.value = value;
}
function Node(left, right) {
this.left = left;
this.right = right;
}
var repmin = trace(function repmin(tree, min) {
switch (tree.constructor) {
case Leaf:
return [new Leaf(min), tree.value];
case Node:
var [left, lmin] = repmin(tree.left, min);
var [right, rmin] = repmin(tree.right, min);
return [new Node(left, right), Math.min(lmin, rmin)];
}
});
为了实现trace
,我们需要提供的本地递归,letrec
以便我们可以编写如下内容:
function trace(f) {
return function (a) {
var [b, c] = f(a, c);
return b;
};
}
我原本是想许下c
诺言的。然而,这改变了trace
. 那么,你能想出一种trace
在 JavaScript 中实现而不改变其语义的方法吗?