12

I was looking at some Haskell source code and came across a pattern match with !_, the code is here: http://hackage.haskell.org/package/base-4.9.0.0/docs/src/GHC.List.html#unsafeTake

take n xs | 0 < n     = unsafeTake n xs
          | otherwise = []

-- A version of take that takes the whole list if it's given an argument less
-- than 1.
{-# NOINLINE [1] unsafeTake #-}
unsafeTake :: Int -> [a] -> [a]
unsafeTake !_  []     = []
unsafeTake 1   (x: _) = [x]
unsafeTake m   (x:xs) = x : unsafeTake (m - 1) xs

I don't really understand how the "strict wildcard" works and why it's useful for this function (or any other function).

Carlos D
  • 180
  • 1
  • 8

1 Answers1

12

The idea is that unsafeTake (and take for that matter), when asked to return the first m elements of the empty list, it should return the empty list, no matter what the value of m is. But what if m is an expression that throws an exception? For example, it would be weird for unsafeTake undefined [] to return []. So we need to ensure that m evaluates to integer even if we don't care what is its exact value (for the empty list case of course). This makes unsafeTake behave the same way when it comes to its first argument, not matter whether the second argument (the list) is empty or not.

redneb
  • 21,794
  • 6
  • 42
  • 54
  • 1
    I suppose it worth mentioning that if you use `take` function with `undefined` as `n` argument then it is unlikely to catch error in `unsafeTake` function because `n` is compared with zero earlier, i.e. it would be evaluated earlier. But because `take` function is supposed to be inlined as much as possible (as comment says) then this check may disappear after some optimizations. That's why we need `!_` in `unsafeTake` as well. – Shersh Sep 11 '16 at 21:10