12

我最近遇到了以下代码,这让我很困扰

lowerSafeForeignCall dflags block
| (entry, middle, CmmForeignCall { .. }) <- blockSplit block
= do
 -- do block stuffs
 -- Block doesn't end in a safe foreign call:
| otherwise = return block

这段代码来自 https://phabricator.haskell.org/rGHCb0534f78a73f972e279eed4447a5687bd6a8308e

在文件 compiler/cmm/CmmLayoutStack.hs

第 983 行

我真的很想知道第二行中这是什么<-。我相信lowerSafeForeignCall是一个函数,而| 和“否则”表示此函数使用警卫。所以

(entry, middle, CmmForeignCall { .. }) <- blockSplit block

必须是 Bool 类型。但是 <- 在任何 do 块之外。我在网上做了一些搜索,但仍然没有关于这种用法的任何线索。

4

2 回答 2

13

那是一个模式守卫

守卫       →   pat <- infixexp      (模式守卫)

[...]

守卫具有以下形式之一:

  • 模式保护的格式为p <- e,其中p是类型t的模式(参见第3.17节),而e是表达式类型t。如果表达式e与模式p匹配,它们就会成功,并将模式的绑定引入环境。

在普通保护仅限于布尔检查的情况下,模式保护可以匹配任意模式并定义局部变量。(在您的情况下entrymiddle和 的内容CmmForeignCall将直接在函数体中可用。)

您可以将布尔守卫视为等同于具有以下模式的模式守卫True

| expr

| True <- expr
于 2019-05-31T10:41:31.967 回答
8

这是一个模式守卫[Haskell-wiki]。从 Haskell'10 开始,后卫就是一个预选赛名单。限定符可以是条件(如旧守卫)和模式守卫

因此,Haskell 将(懒惰地)评估箭头右侧的表达式,<-并旨在将其与箭头左侧的模式匹配。如果成功,那么守卫(以及守卫的那部分)就成功了。如果守卫的所有部分都成功,则规则“触发”。

在这种特定情况下,模式中唯一可能失败的部分是 3 元组的第三项不是CmmForeignCall数据构造函数这一事实。此外,通过使用这个模式守卫,我们当然可以在表达式的主体中使用entry, middle

于 2019-05-31T10:40:57.053 回答