在这种模式匹配中发生了什么?

Mic*_*ard 5 haskell pattern-matching

在Data.List中,我看到了这个不熟悉的模式匹配:

{-# NOINLINE [1] unsafeTake #-}
unsafeTake :: Int -> [a] -> [a] 
unsafeTake !_  []     = []
unsafeTake 1   (x: _) = [x]
unsafeTake m   (x:xs) = x : unsafeTake (m - 1) xs
Run Code Online (Sandbox Code Playgroud)

我的理解是!删除thunk.好的,但_被忽略了.有些东西我不理解.澄清表示赞赏.

Edg*_*rks 3

那是一个BangPattern。它是一个注释,告诉编译器该函数在其第一个参数中应该表现严格。它相当于下面的代码:

unsafeTake :: Int -> [a] -> [a] 
unsafeTake x  []     = x `seq` []
unsafeTake 1   (x: _) = [x]
unsafeTake m   (x:xs) = m `seq` (x : unsafeTake (m - 1) xs)
Run Code Online (Sandbox Code Playgroud)

该字段是严格的,意味着如果第一个参数恰好是底部,则程序将停止:

unsafeTake (error "kaboom") [] 
Run Code Online (Sandbox Code Playgroud)

这将引发带有严格性注释的 kaboom,但如果没有它,则不会发生。

您还可以将 Bang Pattern 放入数据类型定义中:

data Tree a = Branch (Tree a) !a (Tree a)
            | Empty 
Run Code Online (Sandbox Code Playgroud)

然后它总是将包含a 的字段评估为其弱头范式。这意味着它不会评估整个结构。来自哈斯克尔维基

  • 构造函数(最终应用于参数),例如 True、Just (square 42) 或 (:) 1
  • 应用于太少参数(可能没有)的内置函数,例如 (+) 2 或 sqrt。
  • 或 lambda 抽象 \x -> 表达式。

  • 翻译有点正确,但不完全正确。在 bang 模式版本中,即使第二个参数不是“[]”,也会评估“x”。在这种情况下,这并不重要,因为第二个方程无论如何都会计算第一个参数。 (3认同)
  • 抱歉,我的意思是:第一个方程 `unsafeTake !_ [] = []` 意味着第一个参数将始终被计算,无论方程的其余部分以及第二个参数是否为 `[]` 。第一个方程 `unsafeTake x [] = x \`seq\` []` 仅在第二个参数为 `[]` 时强制使用 `x`。 (2认同)