IO monad haskell中的阶乘函数

时间:2015-10-22 01:41:11

标签: haskell io-monad

我正在IO monad haskell中执行阶乘函数。 我按照示例mod3来使用IO monad执行阶乘函数。 我无法理解为什么我的代码错了。 我想看看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 个答案:

答案 0 :(得分:1)

在这部分代码中:

readIORef (n,r2) 

(n,r2)不是IORef。 r2是一个IORef,所以你这是合法的:

readIORef r2

那么试试这个:

  1. 阅读IORef r2获取值
  2. 返回对(n,...),其中......是您在步骤1中获得的值

答案 1 :(得分: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看起来大致对应于命令式代码:

while r2 >= 1 :
  r2 = r2 * fact(r2-1)

这没有意义:为什么递归调用?当然,你知道如何用传统的命令式语言写出命令式的阶乘;从那开始并将其转换为Haskell。

答案 2 :(得分:0)

我看到两个阻止编译的问题。第一个是fact (v2-1)的类型为IO (Integer, Integer),但您尝试将其乘以v2 :: Integer。您需要像序列fact (v2-1)一样对readIORef r2进行排序,乘以该对的第二个组成部分。

其次,你在滥用readIORef。你可以看到它的签名here。它需要IORef a,而不是一对。