Росс Патерсон: Arrows and Computation вводит trace
функцию (на странице 11):Функциональная Pearl: Реализация след в JavaScript
trace :: ((a, c) -> (b, c)) -> a -> b
trace f a = let (b, c) = f (a, c) in b
trace
функция полезна для модульности волшебного шага в обратной circular programs. Например, рассмотрите известную функцию Ричарда Берда 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)];
}
});
в Orde г реализовать trace
нам нужна местная рекурсия, как это предусмотрено letrec
так, что мы можем написать что-то вроде:
function trace(f) {
return function (a) {
var [b, c] = f(a, c);
return b;
};
}
Первоначально я думал сделать c
обещание. Однако это изменяет семантику trace
. Итак, можете ли вы придумать способ реализовать trace
в JavaScript без изменения его семантики?
Вы не можете этого сделать, но, возможно, вы можете подделать его с прокси-объектами. – melpomene