ghci自引用赋值

时间:2014-01-19 22:38:26

标签: haskell ghci

今天我正在学习一些新的Haskell,当时我在ghci中尝试了一些东西。 它基本上归结为:

Prelude> let x = 6
Prelude> x
6
Prelude> let y = show x
Prelude> y
"6"
Prelude> let x = show x
Prelude> x
"\"\\\"\\\\\\\"\\\\\\\\\\\\\\\"\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\"\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\" --(repeats)

那么ghci在作业中不能自我引用吗?我觉得它类似于C中的i = i++;,或者试图在Scheme中引用let(不是let*)的先前分配。无论如何都要这样做,或者我应该使用更简单的let y = show x

4 个答案:

答案 0 :(得分:9)

默认情况下,Haskell中的定义是递归。因此,您为x所做的定义指的是同一个x,这就是您看到的字符串很长的原因,因为x被定义为String这是调用show本身的结果,所以你不断看到显示字符串的开头引号,然后那些开头的引号被转义,依此类推。

这些定义可能非常有用。例如,如果你写:

let fibs = 0 : 1 : zipWith (+) fibs (tail fibs)

你可以将Fibonacci序列本身定义为无限列表。

然后你可以做take 10 fibs之类的事情来看看前10个元素。

答案 1 :(得分:6)

确实是自我参考!它试图解决这个等式

x = show x

由于show返回一个字符串,Haskell知道x"\""那样开始,并且足以猜出第二个字符,这对于第三个字符就足够了第四次就足够了......

等等。

答案 2 :(得分:2)

是的,你可以在ghci中做一个非自我引用的任务,虽然它有点麻烦:

let x = 5
x <- return $ show x

let是递归的,而monadic绑定则不是。

答案 3 :(得分:1)

再次:是的,Haskell在赋值时可以自我引用,否则这只会给出错误,而不是打印出难以辨认的东西,不是吗?

你在Haskell中无法做的事情,永远,是修改/ 重新分配变量的值。这完全是不可能的:如果您曾将x定义为某个值,x将永远保留此值。一种假设被烘焙到非常语言中,并且在编译器中用于很多优化等等。

现在你想知道为什么你可以再次写let x = ...,不是我只是说这是不可能的吗?问题是,你在那里做的是定义一个新的变量也碰巧有名x ,但这并没有改变任何关于具有相同名称的旧变量。你可能会期待这个

Prelude> let x = 6
Prelude> let p = print x
Prelude> let x = 7
Prelude> p

获得7,但实际上它会打印6,因为p仍然引用旧变量x,而不是稍后定义的新变量n :: Int n = 7 f :: IO () f = print $ replicate n "ha" ... -- much later, you've forgotten there was a global `n` up there... g :: String -> String g = take n where n = 37

仍然困惑?也许不那么奇怪的是

f

f将占用37个字符而不是7个字符是合理的,而对g的任何调用仅继续重复字符串7次。毕竟,它是“n,其中 let具有该值”,但除此之外别无其他。现在,where只是do反过来写的。特别是, let x = 6 in ( print x >> ( let y = show x in ( print y >> ( let x = show x in ( print x ) ) ) ) 符号或GHCi提示符实际上是这样的语法糖:

let x = show x in ( print x )

每个paren都包含一个范围。可以使用外部作用域中定义的变量,但如果找到,则优先使用本地变量。因此,x = 6可以完全独立考虑,原始的{{1}}会在此范围内被遮蔽。因此,定义可以工作的唯一方法是递归地引用自身。