views:

235

answers:

3

I seem to remember an older version of F# allowing structural decomposition when matching sequences just like lists. Is there a way to use the list syntax while keeping the sequence lazy? I'm hoping to avoid a lot of calls to Seq.head and Seq.skip 1.

I'm hoping for something like:

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

But this only handles lists and gives a type error when using sequences. When using List.of_seq, it seems to evaluate all the elements in the sequence, even if it is infinite.

+8  A: 

If you use the LazyList type in the PowerPack, it has Active Patterns called LazyList.Nil and LazyList.Cons that are great for this.

The seq/IEnumerable type is not particulaly amenable to pattern matching; I'd highly recommend LazyList for this. (See also http://stackoverflow.com/questions/1306140/f-why-is-using-a-sequence-so-much-slower-than-using-a-list-in-this-example )

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
Brian
link here for anyone who (like me) didn't know what the power pack is: http://fsharppowerpack.codeplex.com/
gatoatigrado
+2  A: 

Seq works fine in active patterns! Unless I'm doing something horrible here...

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

I don't know how to get StackOverflow's code highlighting into F# mode, I think it's using OCaml here so the generic annotation goes wacky...

Dan Fitch
One trick for instances where you want a single single-quote: Add another single-quote in a comment at the end of the line: // '
harms
Its a neat trick, but more than one reliable source indicates that its not a good pattern since evaluating the sequence is O(n^2): http://stackoverflow.com/questions/1306140/f-why-is-using-a-sequence-so-much-slower-than-using-a-list-in-this-example/1306267#1306267
Juliet
True, but the questioner's example is not recursive. This is obviously not good for recursing down the sequence, but if you just want to pattern match on the head or something...
Dan Fitch
A: 

Remember seq has map reduce functions as well, so you might often be able to get away with only those. In the example, your function is equivalent to "Seq.isEmpty". You might try to launch fsi and just run through the tab completion options (enter "Seq." and hit tab a lot); it might have what you want.

gatoatigrado