Question

I need a function that could take an arbitrary number of arguments, each could be either of type 'T or seq<'T>. Inside the function I need to process it as a single seq<'T> with all inputs combined in the same order as they sere supplied.

The obvious way was to have something like:

module Test =
    let flatten ([<ParamArray>] args) =
        let flat = seq {
                for a in args do
                    match box a with
                    | :? int as x -> yield x
                    | :? seq<int> as sq -> 
                        for s in sq do
                            yield s
                    | _ -> failwith "wrong input type"
                }
        flat // this should be seq<int>

but I cannot make it work in FSI even with the simplest case

let fl = Test.flatten 1;;
  ----------------------^

...: error FS0001: The type 'int' is not compatible with the type 'seq<'a>'

What is wrong here and how to get it work as needed? Probably this could be done in some completely different way?

Was it helpful?

Solution

From msdn :

In F#, parameter arrays can only be defined in methods. They cannot be used in standalone functions or functions that are defined in modules.

So instead of a module, declare a type with a static method.

open System
type Test() =
    static member flatten ([<ParamArray>] args: obj[]) =
        let flat = seq {
                for a in args do
                    match box a with
                    | :? int as x -> yield x
                    | :? seq<int> as sq -> 
                        for s in sq do
                            yield s
                    | _ -> failwith "wrong input type"
                }
        flat

If you have other let bindings you can still declare a module with the same name. Also note that in the second guard of the match you can avoid the for loop by doing:

| :? seq<int> as sq -> yield! sq 

And box is not required.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top