32

在我正在阅读的代码库中,我发现了这样的函数声明(缺少某些部分):

filepathNormalise :: BS.ByteString -> BS.ByteString
filepathNormalise xs
    | isWindows, Just (a,xs) <- BS.uncons xs, sep a, Just (b,_) <- BS.uncons xs, sep b
    = '/' `BS.cons` f xs

逗号在这里有什么作用?

(只是作为奖励,如果有人很容易知道这一点:Haskell Programming from first principle中是否提到了这种语法,如果是,在哪里?因为我不记得读过它。)

4

2 回答 2

29

守卫在Haskell 2010 第 3.13 节,案例表达式中进行了描述 (该部分是关于案例表达式,而不是顶级声明,但大概语义是相同的):

guards  →  | guard1, …, guardn      (n ≥ 1)
guardpat <- infixexp         (pattern guard)
        |  let decls               (local declaration)
        |  infixexp                (boolean guard)

对于每个受保护的表达式,逗号分隔的保护从左到右依次尝试。如果它们都成功,则相应的表达式将在使用警卫引入的绑定扩展的环境中进行评估。也就是说,由守卫(通过使用 let 子句或模式守卫)引入的绑定在以下守卫和相应表达式的范围内。如果任何防护失败,则此防护表达式失败并尝试下一个防护表达式。

在简单的情况下,逗号的作用类似于 Boolean. 但是逗号更强大,因为每个守卫都可以引入新的绑定,供后续守卫使用(从左到右进行)。

守卫中的逗号并不常见(至少根据我的经验),我将这个特性描述为 Haskell 琐事——对于编写(或者,在大多数情况下,阅读)Haskell 完全没有必要。我怀疑Haskell Programming 从第一原则中忽略了它。

于 2017-10-01T06:44:59.500 回答
2

这种语法在 Haskell '98 中是不合法的;这被添加到 Haskell 2010 的语言规范中。它是“模式保护”语言扩展的一部分。

https://prime.haskell.org/wiki/PatternGuards

这样做的真正用处在于允许您在保护子句中进行模式匹配。语法更改还具有允许您使用逗号将几个布尔术语“与”在一起的副作用。

(我个人真的不喜欢这个扩展,我有点震惊它进入了官方规范,但我们在那里......)

于 2017-10-02T09:37:28.777 回答