【发布时间】:2017-10-12 05:43:39
【问题描述】:
在haskell中,我可以做到:
s@"Hello" = s
结果是:
>s
>"
它开始打印字符串但永远不会结束,这是怎么回事?
【问题讨论】:
在haskell中,我可以做到:
s@"Hello" = s
结果是:
>s
>"
它开始打印字符串但永远不会结束,这是怎么回事?
【问题讨论】:
@"Hello" 在这里无关紧要,它所做的只是将类型固定为String。你会得到同样的行为
s :: String
s = s
在语义上等价于
s' :: String
s' = undefined
给出结果
Prelude> s'
"*** Exception: Prelude.undefined
我所说的“语义等价”是指,s 和s' 都是底部值的示例,即来自“任何类型包含的错误值的sin bin”的值,这要归功于不严格”。一旦你达到最低值,纯粹的 Haskell 语言基本上是无能为力的,并且已经屈服于,嗯,undefined,“不纯行为”,比如让你永远等待或抛出异常。 p>
但是,再次感谢非严格性,这不一定会发生。当打印一个值时,首先发生的是,Show 实例被调用并被要求生成一个字符串。 Haskell 字符串是一个惰性列表。而 any 字符串的show 以" 开头,因此即使字符串本身完全未定义,show 也会设法产生那个字符。
我们可以更隐蔽地观察到这一点
Prelude> head $ show s
'"'
【讨论】:
在lets 和顶级表达式中,= 左侧的所有内容都在右侧的范围内。所以你已经创建了一个循环的“底部”值。
请注意,其行为方式相同:
Prelude> let s = (s::String)
Prelude> s
"
这是因为(简化)String 上的print 被定义为等同于:
printString chars = putChar '"' >> mapM_ putChar chars
因为chars 是一个循环,所以mapM_ putChar chars 似乎挂起。
【讨论】:
let 1=2。你能解释一下吗?
let x@1 = 2 in x 会失败,let !1 = 2 in () 也会失败。但是使用let 1 = 2 in (),没有什么会迫使 Haskell 实际执行请求的模式匹配。