Я давал ответ на этот вопрос, и мне пришла идея использовать монаду Cont
. Я недостаточно знаю Haskell, чтобы объяснить, почему эта программа не работает.
import Control.Monad.Cont
fib1 n = runCont (slow n) id
where
slow 0 = return 0
slow 1 = return 1
slow n = do
a <- slow (n - 1)
b <- slow (n - 2)
return a + b
main = do
putStrLn $ show $ fib1 10
Ошибка -
main.hs:10:18: error:
• Occurs check: cannot construct the infinite type: a2 ~ m a2
• In the second argument of ‘(+)’, namely ‘b’
In a stmt of a 'do' block: return a + b
In the expression:
do a <- slow (n - 1)
b <- slow (n - 2)
return a + b
• Relevant bindings include
b :: a2 (bound at main.hs:9:7)
a :: a2 (bound at main.hs:8:7)
slow :: a1 -> m a2 (bound at main.hs:5:5)
|
10 | return a + b
|
Но это не имеет для меня смысла. Почему у меня a2
и m a2
? Я ожидаю, что a
и b
будут одного типа.
Меня это беспокоит, потому что та же самая программа отлично работает в JavaScript. Может быть, для Haskell нужна подсказка типа?
const runCont = m => k =>
m (k)
const _return = x =>
k => k (x)
const slow = n =>
n < 2
? _return (n)
: slow (n - 1) (a =>
slow (n - 2) (b =>
_return (a + b)))
const fib = n =>
runCont (slow(n)) (console.log)
fib (10) // 55
return a + b
анализируется как(return a) + b
. Вместо этого попробуйтеreturn (a + b)
илиreturn $ a + b
. - person Joseph Sible-Reinstate Monica   schedule 24.02.2019where
. Это также упрощает (и ускоряет) чтение кода. - person David Young   schedule 24.02.2019