4

This is an example taken from o' reilly - real world haskell.

maybeReview alist = do
  title <- lookup1 "title" alist
  return (MovieReview title)'

lookup1 key alist = case lookup key alist of
                      Just (Just s@(_:_)) -> Just s
                      _ -> Nothing

How does the @ symbol work here in the line,

Just (Just s@(_:_)) -> Just s

How does it match a non-empty value?

  • I'd have used a guard: `Just (Just s) | not (null s) -> Just s`. –  Jul 15 '15 at 07:50
  • Although yours is not the case, it is good to know such pattern can [force strictness](http://stackoverflow.com/questions/15627849/turn-off-lazy-evaluation-in-haskell) (see Daniel Wagner's comment under the first answer). – rem Jul 15 '15 at 15:25

2 Answers2

11

_ is a wildcard. It says make sure there is a value here but I don't want to bind it to any variable. : is the constructor for a list. On the left is one value and the right is the rest of the list. The rest of the list can be empty. So if you do something like this:

(x:xs)

x is the first element of the list and xs can be an empty list or it can be an infinite amount of elements.

(x:y:xs)

Would only match lists with at least 2 elements. The @ is the at pattern. It binds the entirety of the right expression to the left variable.

m@(Just _)

Here m would have the type Maybe a. The _ is just used because Just is of type a -> Maybe a and we need to have a placeholder for its argument. So m binds to the whole value of (Just _). In your example.

s@(_:_)

s is the whole list. And (_:_) specifies that the list must have at least one element or the match will fail. If we wrote:

s@(x:xs)

x would be the first element and xs would be the tail of the list. s == x:xs would return True. But since we don't need the head or the tail we simply use _.

zsmb13
  • 85,752
  • 11
  • 221
  • 226
DiegoNolan
  • 3,766
  • 1
  • 22
  • 26
5

An explanation by examples...

Let "the pattern" refer to Just (Just s@(_:_)). Below is a list of various values and whether or not those values match the pattern. If there is a match then s will be set to a part of the value and can be used on the RHS of the pattern guard.

  1. value = Nothing - does not match

  2. value = Just Nothing - does not match

  3. value = Just (Just []) - does not match

  4. value = Just (Just [3,4,5]) - matches and s = [3,4,5]

  5. value = Just (Just [6]) - does match and s = [6]

  6. value = Just (Just [1,2]) - matches and s = [1,2]

ErikR
  • 51,541
  • 9
  • 73
  • 124