views:

130

answers:

3

Hi all,

Is there a multiple instances pattern in F# somewhere?

Consider that I'm working on a list. I have the following pattern matching

match l with
| [] | [_] -> l  //if the list is empty or contains only one item, simply return it
|        

    //is there a pattern to test if all of the elements are identical?

In other words passing [] or [1] should simply return the list and so should [1;1;1;...] but I can't figure out how to pattern match that last pattern. Is this possible? Or is there a better approach that I might use? I haven't found anything anywhere about a repeating pattern.

+3  A: 

I don't know of any pattern that does what you want, but you could do this:

let allSame L =
    match L with
    | [] | [_] -> L
    | h::t when t |> List.forall ((=) h) -> L
    | _ -> failwith "unpossible!" //handle the failing match here

P.S. You're talking about a sequence, but your match indicates that you're working with a list. The corresponding code for a sequence would be something like

let allSameSeq s = 
    match Seq.length s with
    | 0 | 1 -> s
    | _ when Seq.skip 1 s |> Seq.forall ((=) (Seq.head s)) -> s
    | _ -> failwith "unpossible!"

Be warned that the performance of this function may well be worse than the list-based one.

cfern
@cfern, You're right. I do need to be careful about the terminology I use. I tend to use "List" and "Sequence" as if they were synonyms--and in F# they're definitely not synonymous. I am working with a list.
Onorio Catenacci
A: 

I'd consider doing one of the following:


yourSequence |> Seq.windowed(2) |> Seq.forall(fun arr -> arr.[0] = arr.[1])

or


let h = Seq.hd yourSequence
yourSequence |> Seq.forall((=) h)

It's always good to use library functions when possible ;)

emaster70
+3  A: 

Here is a solution using multi-case active patterns.

let (|SingleOrEmpty|AllIdentical|Neither|) (lst:'a list) =
    if lst.Length < 2 then
        SingleOrEmpty
    elif List.forall (fun elem -> elem = lst.[0]) lst then
        AllIdentical
    else
        Neither

let allElementsIdentical lst:'a list =
    match lst with
    |SingleOrEmpty|AllIdentical -> lst
    |Neither -> failwith "Not a suitable list"
m-sharp