Не зная, что делает ваша repeat
функция, я предполагаю, что ваш вызов repeat(10)(inc)(0)
должен расшириться до
map(inc)(
map(inc)(
map(inc)(
map(inc)(
map(inc)(
map(inc)(
map(inc)(
map(inc)(
map(inc)(
map(inc)(
of(0)
)
)
)
)
)
)
)
)
)
)
Поскольку ваш inc
по какой-то причине возвращает функцию _ => Int
вместо простого Int
, это вызовет x + 1
для функции x
, что приведет к строковому определению этой функции (y => x
становится "y => x1"
), что вызовет исключение при попытке вызова.
После исправления const inc = x => x + 1;
ваша функция repeat
по-прежнему не работает.Это должна быть простая рекурсия, с
const id = x => x
// rec :: ((a -> c, b -> c, a) -> c) -> a -> b
// here with c == b, no trampoline
const rec = f => x => f(rec(f), id, x) // a bit like the y combinator
const repeat = n => f => x =>
rec((loop, done, [m, g]) =>
m === 0
? done(g)
: loop([m - 1, map(f)(g)])
)([n, of(x)]);
repeat(10)(inc)(0)() // 10 - works!
Монада не задействована вообще!
Если бы мы хотели использовать chainRec
, нам нужно было бы ввести некоторую произвольную монаду (здесь: функция-монада) и обратный вызов f
на chainRec
должен будет возвращать экземпляр этого типа монады вместо loop
/ done
:
chainRec :: ChainRec m => ((a -> c, b -> c, a) -> m c, a) -> m b
// ^
Мы могли бы сделать этопросто упаковав возвращаемое значение в of
:
const repeat = n => f => x =>
chainRec((loop, done, [m, g]) =>
of(m === 0
// ^^
? done(g)
: loop([m - 1, map(f)(g)])
)
)([n, of(x)]);
и, конечно, теперь получим m b
, то есть все, что обернуто в еще одну функцию:
repeat(10)(inc)(0)()() // 10
// ^^
// repeat(1)(inc)(0) expands to `of(map(inc)(of(0)))
Но я сомневаюсьэто то, что вы хотели.