为什么这个Haskell代码永远不会终止? [英] Why this Haskell code never terminates?

查看:104
本文介绍了为什么这个Haskell代码永远不会终止?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

最近我写了一些Haskell代码,它永远不会终止。在仔细检查我的代码后,问题归结为以下代码块:

  main :: IO()
main = print $ let a = 10 in
let a = a in
a :: Int

我想这与Haskell的懒惰有关,因为相同的代码在OCaml中终止。但是,如果我写了下面的代码而不是

  main :: IO()
main = print $ let a = 10 in
let b = a in
b :: Int

根本没有问题。由于在原始代码中我不能理解这个原因,所以这两个a应该被认为是两个不同的变量。我不知道为什么它们的命名与程序的语义有什么关系。

解决方案

问题是, ,与OCaml不同,Haskell中的 let 绑定默认为递归。所以 let x = x in ... 相当于OCaml的 let rec x = x in ... 一个循环定义。

这就是为什么在Haskell中映射变量名称(即多次定义 a )被认为是不好的原因风格,甚至有一个编译器警告,您可以打开 -Wall 标志或更具体地 -fwarn-name-shadowing

这个默认值在Haskell中比OCaml更有意义,因为懒惰,循环值(而不仅仅是递归函数)实际上是有用的。 let x = 1:x 给了我们无限的 1 列表,我们可以像普通列表一样使用它。与此同时,有些人并不喜欢这一点,基本上就是你碰到这里的原因:可能会在你的代码中引入不直观的无限循环,这使得一些错误和拼写错误难以追查。这也令人困惑,因为必要时,默认情况下,do_meation 中的< - 绑定不是递归的,这有点不一致。

I recently wrote some Haskell code and it never terminates. After I carefully examined my code, the problem boiled down to the following code piece

main :: IO ()
main = print $ let a = 10 in
               let a = a in
               a :: Int

I guess this must have something to do with the laziness of Haskell since the same code terminates in OCaml. However, if I wrote the following code instead

main :: IO ()
main = print $ let a = 10 in
               let b = a in
               b :: Int

the code would have no problem terminating at all. I can't get the reason since in the original code, the two a's should be considered as two different variables. I don't know why the naming of them has anything to do with the semantic of the program.

解决方案

The issue is that, unlike OCaml, let bindings in Haskell are recursive by default. So let x = x in ... is equivalent to OCaml's let rec x = x in ... and is a circular definition.

This is why shadowing variable names in Haskell (ie defining a multiple times) is considered bad style and even has a compiler warning, which you can turn on with the -Wall flag or more specifically -fwarn-name-shadowing.

This default makes more sense in Haskell than OCaml because, thanks to laziness, circular values (rather than just recursive functions) are actually useful. let x = 1:x gives us an infinite list of 1, which we can use just like a normal list.

At the same time, some people don't like this for basically exactly the reason you ran into here: it's possible to introduce unintuitive infinite loops in your code, which makes some errors and typos harder to track down. This is also confusing because, by necessity, <- bindings in do-notation are not recursive by default, which is a bit inconsistent.

这篇关于为什么这个Haskell代码永远不会终止?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆