Можно ли сопоставить с разложенными последовательностями в 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." И сильно нажмите вкладку); это может иметь то, что вы хотите.