Вопрос о операторах ~ и @в Haskell

Что именно они делают? Я знаю одно возможное использование @(назначение имени в начале совпадения с шаблоном), но не удалось найти что-либо на ~.

Я нашел их в следующем фрагменте кода, взятом из http://www.haskell.org/haskellwiki/Prime_numbers, но в статье предполагается, что вы свободно владеете синтаксисом Haskell и не беспокоит объяснение своих эзотерических операторов (часть, с которой я запутался, является началом декларации для сита):

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

Любое объяснение (или ссылка на одно) о синтаксисе, используемом здесь, будет с благодарностью.

Ответы

Ответ 1

Оператор ~ делает совпадение ленивым. Обычно совпадение шаблонов оценивает аргумент, так как необходимо проверить, не сработал ли шаблон. Если вы префикс шаблона с ~, оценка пока не будет необходимой. Эта функциональность часто используется в коде "Tying the knot" , где нужно ссылаться на структуры, которые еще не созданы. Если шаблон не удался после evaulation, результат будет undefined.

Вот пример:

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

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

f [] дает False, а g [] дает true, потому что первый шаблон всегда соответствует. (Вы действительно получаете предупреждение для этого кода)

Таким образом, вы можете видеть ~ как противоположность !, который заставляет оценивать аргумент, даже если он не нужен.

Обратите внимание, что эти операторы только делают вещи строгими/ленивыми на уровне, на котором они применяются, а не рекурсивно. Например:

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

Соответствие шаблону в кортеже строгое, но шаблон совпадений ленив.

Ответ 2

Это ленивое соответствие шаблону (также известное как неопровержимое совпадение с образцом, которое, по моему мнению, является лучшим именем).

По существу, ~(_:t) всегда будет совпадать, даже если вход является пустым списком []. Конечно, это опасно, если вы не знаете, что делаете:

Prelude> let f ~(_:t) = t in f []
*** Exception: <interactive>:1:4-15: Irrefutable pattern failed for pattern (_ : t)