Можно ли сопоставить с разложенными последовательностями в F#?

Кажется, я помню более старую версию F#, допускающую структурную декомпозицию при сопоставлении последовательностей, как списки. Есть ли способ использовать синтаксис списка при сохранении последовательности ленивым? Я надеюсь избежать множества обращений к Seq.head и Seq.skip 1.

Я надеюсь на что-то вроде:

let decomposable (xs:seq<'a>) =
   match xs with
   | h :: t -> true
   | _ -> false
seq{ 1..100 } |> decomposable

Но это только обрабатывает списки и дает ошибку типа при использовании последовательностей. При использовании List.of_seq кажется, что он оценивает все элементы в последовательности, даже если она бесконечна.

3 ответа

Решение

Если вы используете тип LazyList в PowerPack, у него есть активные шаблоны с именами LazyList.Nil и LazyList.Cons, которые отлично подходят для этого.

Тип seq/IEnumerable не особенно подходит для сопоставления с образцом; Я очень рекомендую LazyList для этого. (См. Также Почему использование последовательности намного медленнее, чем использование списка в этом примере.)

let s = seq { 1..100 }
let ll = LazyList.ofSeq s
match ll with
| LazyList.Nil -> printfn "empty"
| LazyList.Cons(h,t) -> printfn "head: %d" h

Seq отлично работает в активных шаблонах! Если я не делаю что-то ужасное здесь...

let (|SeqEmpty|SeqCons|) (xs: 'a seq) = //'
  if Seq.isEmpty xs then SeqEmpty
  else SeqCons(Seq.head xs, Seq.skip 1 xs)

// Stupid example usage
let a = [1; 2; 3]

let f = function
  | SeqEmpty -> 0
  | SeqCons(x, rest) -> x

let result = f a

Я не знаю, как перевести подсветку кода Stackru в режим F#, я думаю, что здесь используется OCaml, поэтому общая аннотация становится дурацкой...

Помните, что в seq также есть функции сокращения карт, так что вы часто можете обходиться без них. В этом примере ваша функция эквивалентна "Seq.isEmpty". Вы можете попытаться запустить fsi и просто запустить опции завершения вкладки (введите "Seq." И сильно нажмите вкладку); это может иметь то, что вы хотите.

Другие вопросы по тегам