Question about the ~ and @ operators in Haskell
Asked Answered
G

2

14

What exactly do they do? I know one possible use of @ (assigning a name at the start of a pattern match), but haven't been able to find anything on ~.

I found them in the following code snippet, taken from http://www.haskell.org/haskellwiki/Prime_numbers, but the article assumes that you're fluent in Haskell syntax and doesn't bother explaining its esoteric operators (the part I'm confused about is the start of the declaration for sieve):

primesPT () = 2 : primes'
  where 
    primes' = sieve [3,5..] primes' 9
    sieve (p:xs) ps@ ~(_:t) q
       | p < q   = p : sieve xs ps q
       | True    =     sieve [x | x<-xs, rem x p /= 0] t (head t^2)

Any explanation (or link to one) about the syntax used here would be greatly appreciated.

Grimona answered 21/9, 2011 at 21:9 Comment(1)
haskell.org/haskellwiki/Keywords is a pretty good place to look up un-Googleable thingsDaguerre
S
11

The operator ~ makes a match lazy. Usually a pattern-match evaluates the argument, as there is a need to check whether the pattern fails. If you prefix a pattern with ~, there is no evaluation until it is needed. This functionality is often used in “Tying the knot” code, where one needs to refer to structures that are not yet created. If the pattern fails upon evaulation, the result is undefined.

Here is an example:

f (_:_) = True
f []    = False

g ~(_:_) = True
g []     = False

f [] yields False, while g [] yields true, because the first pattern always matches. (You actually get a warning for this code)

That said, you can see ~ as the opposite of !, which forces the evaluation of an argument even if it's unneeded.

Note that these operators only make things strict/lazy at the level they are applied at, not recursively. For example:

h ~((x,y):xys) = ...

The pattern match on the tuple is strict, but the cons pattern is lazy.

Soloma answered 21/9, 2011 at 21:19 Comment(0)
K
9

It's a lazy pattern match (also known as irrefutable pattern match which I think is the better name).

Essentially, ~(_:t) will always match, even if the input is the empty list []. Of course, this is dangerous if you don't know what you're doing:

Prelude> let f ~(_:t) = t in f []
*** Exception: <interactive>:1:4-15: Irrefutable pattern failed for pattern (_ : t)
Kylix answered 21/9, 2011 at 21:19 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.