2

这是我被分配调试的 Haskell 程序的一部分:

process :: Sentence -> IO ()
process this@(Sentence string _) = do
  render string
  render "==>"
  render $ translate this

render = putStrLn

data Sentence = Sentence String Task

translate :: Sentence -> String     ; Incomplete Definition
translate (Sentence string task)
  | ...

  | ...

  | ...

  | ...

这个程序的唯一部分我不理解或不认识是process this@(Sentence string _) = do 我以前从未见过的行this@,我也不太确定下划线的(Sentence string _)含义。

4

3 回答 3

7

this@是一个'as-pattern'_的例子,而是一个通配符模式的例子。当我们不关心模式中那个点的值是什么时,使用通配符模式,因此_在模式中将匹配任何内容,并且它不绑定任何本地名称/变量。

另一方面,当我们想绑定一个额外的本地名称/变量同时匹配它时,我们使用 as 模式。你可以考虑一下

process this@(Sentence string _) = ...

大致相当于

process this = let (Sentence string _) = this
               in ...

它将符号左侧给出的额外名称绑定@到它匹配的任何值。at 模式本身匹配所有内容,但符号右侧的内部模式@也匹配它匹配的任何内容 - 并且该模式很可能不匹配所有内容,在这种情况下它仅匹配Sentence构造函数。

正因为如此,如果 let 绑定中的模式匹配失败,at 模式版本和带有 let 绑定的版本会有不同的行为,所以当我们为一个函数定义多个 case 时,通常首选 at 模式,因为它允许内部模式也会影响调用函数的哪种情况。例如

safeHead xs = let (x:_) = xs in Just x
safeHead [] = Nothing

调用时会失败[],因为第一个参数的模式匹配xs成功,所以函数的第一个案例被调用,然后xs无法匹配到(x:_)。但是,如果我们用 as 模式写这个:

safeHead xs@(x:_) = Just x
safeHead [] = Nothing

调用 with[]可以正常工作,因为在我们决定使用函数的第一种情况之前,还会检查内部模式,因此虽然xs匹配[],(x:_)也匹配[],但失败了,所以然后调用第二种情况。我意识到这是一个非常愚蠢的例子,尤其是当我们第二次不使用 xs 时,但我希望它能说明不同之处。

于 2013-03-07T18:48:32.743 回答
4

@定义了一个as 模式,它允许您命名要匹配的事物。在这种情况下,是您匹配this的值的名称。Sentence

于 2013-03-07T18:34:03.203 回答
4

Sentence作为一个接受 aString和 a的构造函数Task,在 patternthis@(Sentence string _)中,this是一个as 模式,它命名整个 Sentence,string命名 Sentence's String,并且下划线位于Task原本应该命名的地方,本质上说Task应该在那里忽略。

于 2013-03-07T18:42:30.233 回答