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

时间:2016-12-19 19:15:11

标签: 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

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

2 个答案:

答案 0 :(得分:4)

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

unsafeTake :: Int -> [a] -> [a] 
unsafeTake x  []     = x `seq` []
unsafeTake 1   (x: _) = [x]
unsafeTake m   (x:xs) = m `seq` (x : unsafeTake (m - 1) xs)

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

unsafeTake (error "kaboom") [] 

这将使kaboom具有严格的注释,但如果它没有它,它将不会发生。

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

data Tree a = Branch (Tree a) !a (Tree a)
            | Empty 

然后它将始终将包含 a 的字段评估为其弱头正常形式。这意味着它不会评估整个结构。来自haskell wiki

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

答案 1 :(得分:1)

它告诉编译器即使第二个参数是[],然后它知道它可以应用第一个替代,它仍然应该评估第一个参数为head normal form。这意味着unsafeTake在其第一个参数中是'严格'。

如果您尝试评估unsafeTake (last (repeat 0)) []take相比,则可以看到结果。