Haskell稀有模式匹配

7
在Haskell中,我可以这样做:
s@"Hello" = s 

结果如下:
>s
>"

开始打印字符串但是从未结束,发生了什么事情?

2个回答

10

@"Hello"在此无关紧要,它只是将类型固定为String。您可以使用相同的方法:

s :: String
s = s

这与语义上等同于

s' :: String
s' = undefined

提供结果

Prelude> s'
"*** Exception: Prelude.undefined

“语义上等价”是指,ss'都是“底部值”的示例,即任何类型都包含的“错误值集合”,因为类型是非严格的。一旦遇到底部值,纯Haskell语言基本上就无能为力了,只能让步于“未定义”,“不纯的行为”,比如让你永远等待或抛出异常。

然而,再次由于非严格性,这并不一定会发生。打印一个值时,首先发生的是调用Show实例,并要求生成一个字符串。Haskell字符串是一个惰性列表。而任何字符串的show都以"开头,因此即使字符串本身是未定义的,show也能够生成那一个字符。

我们可以更加安全地观察这个问题:

Prelude> head $ show s
'"'

哇,这是一个完美的解释,即使我对这个问题有了更多的理解,非常感谢!很高兴在这里有大师们围绕。 - developer_hatch

8
在 let 和顶层表达式中,等号左侧的所有内容都在等号右侧的作用域内。因此,您已经创建了一个循环“底部”值。
请注意,这与以下行为相同:
Prelude> let s = (s::String)
Prelude> s
"

那是因为(简化)在String上print的定义相当于:
printString chars = putChar '"' >> mapM_ putChar chars

因为chars是一个循环,所以mapM_ putChar chars看起来会挂起。

如果你在这里...尝试调查这种行为时,我发现你可以毫无后果地执行 let 1=2。你能解释一下吗? - Eugene Sh.
1
@Eugene:这与懒惰有关——只要您从未检查过该值,模式匹配就不会失败。因此,let x@1 = 2 in x将失败,let !1 = 2 in ()也将失败。但是对于let 1 = 2 in (),没有任何东西会强制Haskell实际执行所请求的模式匹配。 - Antal Spector-Zabusky
@Damian:是的,这是同一件事。(请注意,let体中的“True”与模式匹配中的“True”不同!)更多类似的问题最好作为一个新问题提出 :-) - Antal Spector-Zabusky
@DamianLattenero 那不是我 :) - Eugene Sh.
1
@EugeneSh。另请参见:关于 `let 5 = 10` 的问题 - duplode
显示剩余5条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接