Факториальная функция в IO монаде haskell
Я делаю факториальную функцию в haskell монады IO. Я последовал примеру mod3, чтобы выполнить функцию факториала с монадой ввода-вывода. Я не могу понять, почему мой код неверен. Я хочу посмотреть, если n>=1, а затем сделать факториал для n. Наконец добавление к (n,r2) и возврат. Кто-нибудь может помочь понять это?
while :: IO Bool -> IO () -> IO ()
while test body =
do b <- test
if b
then do {body ; while test body} -- same-line syntax for do
else return ()
-- remainder when integer-dividing n by 3
mod3 :: Integer -> IO Integer
mod3 n = do r <- newIORef n
while
(do {v <- readIORef r; return (v >= 3)})
(do {v <- readIORef r; writeIORef r (v-3)})
readIORef r
-- ghci> fact 4
-- (4,24)
fact :: Integer -> IO (Integer, Integer)
fact n = do r2 <- newIORef n
while
(do {v2 <- readIORef r2; return (v2 >= 1)})
(do {v2 <- readIORef r2; writeIORef r2 (v2*fact(v2-1))})
readIORef (n,r2)
3 ответа
В этой части вашего кода:
readIORef (n,r2)
(n,r2)
это не IORef. r2
это IORef, так что вы это законно:
readIORef r2
Как насчет того, чтобы попробовать это:
- прочитайте IORef r2 для получения значения
- вернуть пару (n, ...) где... это значение, которое вы получили в шаге 1
Во-первых, отступ в аргументах while
В противном случае они являются новыми заявлениями.
fact :: Integer -> IO (Integer, Integer)
fact n = do r2 <- newIORef n
while
(do {v2 <- readIORef r2; return (v2 >= 1)})
(do {v2 <- readIORef r2; writeIORef r2 (v2*fact(v2-1))})
readIORef (n,r2)
Во-вторых, внешний вид пока примерно соответствует императивному коду:
while r2 >= 1 :
r2 = r2 * fact(r2-1)
Это не имеет смысла: почему рекурсивный вызов? Конечно, вы знаете, как написать факториал в императивном стиле на обычном императивном языке; Начните с этого и конвертируйте его в Haskell.
Я вижу две проблемы, которые мешают компиляции. Во-первых, это fact (v2-1)
имеет тип IO (Integer, Integer)
, но вы пытаетесь умножить его на v2 :: Integer
, Вам нужно последовательность fact (v2-1)
как вы последовательность readIORef r2
умножьте на второй компонент пары.
Во-вторых, вы злоупотребляете readIORef
, Вы можете увидеть его подпись здесь. Требуется IORef a
, а не пара.