-3

我在 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) 
4

3 回答 3

1

在这部分代码中:

readIORef (n,r2) 

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

readIORef r2

那么如何尝试这个:

  1. 读取 IORef r2 获取值
  2. 返回 (n, ...) 对,其中 ... 是您在步骤 1 中获得的值
于 2015-10-22T02:47:10.790 回答
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。

于 2015-10-22T08:59:43.393 回答
0

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

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

于 2015-10-22T02:48:10.217 回答