【问题标题】:In haskell loop exception without loop in its function body在函数体中没有循环的haskell循环异常中
【发布时间】:2015-01-20 10:48:52
【问题描述】:

我是 Haskell 的新手并编写了以下小代码,但它因循环异常而失败。问题是代码不使用循环,甚至递归。 这让我发疯了!

gameList :: [Int]->Int->Int->[(Int, Int)]
gameList  org pos step =
    let next  = (mod (pos + step)  2) ;
        pos = next;             
    in  [(pos, pos)]

然后将其保存在一个文件中,并以交互模式成功将其加载到 GHC 中。 像这样调用它 gameList [1,2,3] 0 1

它会抛出错误“[(***异常:”

GHCI 信息:WinGHCi 1.0.6 帮帮我!

【问题讨论】:

  • 这里无限循环,因为pos 是您的论据之一。你想做什么? gameList [1,2,3] 0 1 的预期输出是什么?
  • 顺便说一句,你通常不需要在 Haskell 中用分号结束行,也不需要用括号包围定义。
  • 原因是let表达式不是赋值,是块代码的定义。在这种情况下,它是递归的。与下面代码相同的情况: let t = (let pos = next; next = pos in (pos, next))

标签: haskell ghci


【解决方案1】:

“不使用循环,甚至递归”

恐怕它确实使用了递归,尽管在非惰性语言中甚至不可能使用递归!

关键在于您的参数pos 从未在任何地方实际使用过,它立即被let 块中定义的pos 遮蔽(GHC 会警告您这一点,使用-Wall!)。所以你的代码相当于

gameList org _ step =
    let next  = (mod (pos + step)  2) ;
        pos = next;             
    in  [(pos, pos)]

其中next 是根据pos 定义的,next 是...等等。

明显的解决方法是删除pos = next 行,无论如何这完全没有必要。

gameList org pos step
  = let next  = (pos + step) `mod` 2
    in  [(next, next)]

【讨论】:

  • 我明白了我误解 let 表达式含义的原因。这不是作业,而是代码块。也感谢您对 -Wall 的回答和建议
  • 这是一组定义,这很关键。
【解决方案2】:

不使用循环,甚至递归

这不正确,原因如下。

gameList :: [Int]->Int->Int->[(Int, Int)]
gameList  org pos step =              -- this is an unused argument named pos
  let next  = (mod (pos + step)  2) ; -- here we define next in terms of pos
        pos = next;                   -- ... which is defined here in terms of next
    in  [(pos, pos)]                  -- here we use this circularly-defined pos

看,let 不是赋值,也不是从上到下“执行”的。 let 引入了一个相互递归定义的块。所以这个

let next  = (mod (pos + step)  2) ;
    pos = next;             

根本不使用pos 函数参数。

【讨论】:

  • 是的,我犯了这个错误,因为我认为 let 表达式只是赋值,而不是代码块。所以我很难知道为什么。非常感谢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-12-06
  • 1970-01-01
  • 2019-01-17
  • 1970-01-01
相关资源
最近更新 更多