Начиная с правильно сформированной взаимно рекурсивной пары -
// map :: (a -> b, Tree a) -> Tree b
const map = (f, [ v, children ]) =>
Node (f (v), ...mapAll (f, children))
// mapAll :: (a -> b, [ Tree a ]) -> [ Tree b ]
const mapAll = (f, nodes = []) =>
nodes .map (n => map (f, n))
Сначала мы удаляем нетерпеливое Array.prototype.map
, которое не может допустить форму хвоста -
const map = (f, [ v, children ]) =>
Node (f (v), ...mapAll (f, children))
const mapAll = (f, [ node, ...more ]) =>
node === undefined
? []
: [ map (f, node), ...mapAll (f, more) ]
Затем добавляемпараметр для преобразования CPS -
const identity = x =>
x
const map = (f, [ v, children ], k = identity) =>
mapAll (f, children, newChilds => // tail
k (Node (f (v), ...newChilds))) // tail
const mapAll = (f, [ node, ...more ], k = identity) =>
node === undefined
? k ([]) // tail
: map (f, node, newNode => // tail
mapAll (f, more, moreChilds => // tail
k ([ newNode, ...moreChilds ]))) // tail
Проверьте результаты в своем браузере ниже
const Node = (x, ...xs) =>
[ x, xs ]
const identity = x =>
x
const map = (f, [ v, children ], k = identity) =>
mapAll (f, children, newChilds =>
k (Node (f (v), ...newChilds)))
const mapAll = (f, [ node, ...more ], k = identity) =>
node === undefined
? k ([])
: map (f, node, newNode =>
mapAll (f, more, moreChilds =>
k ([ newNode, ...moreChilds ])))
const tree =
Node
( 1
, Node
( 2
, Node (3)
, Node
( 4
, Node (5)
)
)
, Node (6)
, Node
( 7
, Node (8)
, Node (9)
, Node (10)
, Node (11)
)
)
console.log (map (x => x * 10, tree))
Обратите внимание, что CPS сама по себе не делает программу безопасной для стека.Это просто форма, необходимая для размещения кода на батуте по вашему выбору.