В "Программировании F#" я столкнулся с сопоставлением с образцом как этот (я упростил немного):
let rec len list =
match list with
| [] -> 0
| [_] -> 1
| head :: tail -> 1 + len tail;;
Практически, я понимаю, что последнее соответствие распознает голову и хвост списка. Концептуально, я не добираюсь, почему это работает. Насколько я понимаю:: оператор недостатков, который добавляет значение в положении головы списка, но это не смотрит на меня как он, используется в качестве оператора здесь. Если я понимаю это как "специальный синтаксис" для списков, где:: интерпретируется как оператор или "шаблон соответствия" в зависимости от контекста? Или та же идея может быть расширена для типов кроме списков с другими операторами?
В дополнение к ответу Брайана, есть несколько моментов, которые стоит отметить. Синтаксис h::t
может использоваться и как оператор и как шаблон:
let l = 1::2::[] // As an operator
match l with x::xs -> 1 | [] -> 0 // As a pattern
Это означает, что это немного специальная конструкция, потому что другие операторы (например, +
) не могут использоваться как шаблоны (для разложения результата обратно на аргументы оператора) - очевидно, что для +
это было бы неоднозначно.
Также интересен паттерн [_]
, поскольку он является примером вложенного паттерна. Он состоит из:
_
- шаблон Underscore, который соответствует любому значению и не связывает никаких символов [ <шаблон> ]
- шаблон одноэлементного списка, который соответствует списку с одиночными элементами и соответствует элементу списка с вложенным <шаблоном>
. Вы также можете написать match 1::[] с | [x] -> x
, который вернет значение единственного элемента (в данном случае 1).
Он используется как средство форматирования или формально шаблон
, «список» сопоставляется с тремя шаблонами:
[] означает, что список пуст
[_] означает, что в списке один элемент, так как вам все равно, что это за элемент, поэтому просто поместите туда _, вы также можете использовать [a].
head :: tail означает, что список действительно состоит из двух частей: головы и хвоста.
Вы можете рассматривать сопоставление с образцом F # как мощную структуру if then else.
Это специальный синтаксис для списков. Вы можете представить тип list
как дискриминированное объединение следующим образом:
type list<'T> = // '
| Nil
| Cons of 'T * list<'T>
за исключением того, что существует специальный синтаксис, который заставляет Nil
быть []
и Cons(h,t)
быть h::t
. Тогда это просто обычное сопоставление с образцом на дискриминированном объединении. Помогло?
(Возможно, см. также эту запись в блоге.)
.