8

is there a way to flatten tuples of arbitrary size in F# without explicitly mapping them?

(fun ((((a0,a1),a2),b),c) ->  (a0,a1,a2,b,c))

As a note I'm getting these kind of tuples from FParsec but the capability would be convenient if it was available generally.

thanks,

Koenig Lear
  • 2,366
  • 1
  • 14
  • 29

1 Answers1

4

You can't do it easily, but with a bit of reflection it is possible:

let isTuple tuple =
    Microsoft.FSharp.Reflection.FSharpType.IsTuple(tuple.GetType()) 

let tupleValues (tuple : obj) = 
    Microsoft.FSharp.Reflection.FSharpValue.GetTupleFields tuple |> Array.toList

let rec flatten tupleFields =
    tupleFields |> List.collect(fun value ->
        match isTuple value with
        | true -> flatten (tupleValues value)
        | false -> [value]
    )

let tupleToList (tuple : obj) = 
    if isTuple tuple
        then Some (tupleValues tuple |> flatten)
        else None

So, for example:

let s = tupleToList ((100,101,102,103),1,2,3,(4,5))

Will give you:

[100; 101; 102; 103; 1; 2; 3; 4; 5]

NOTE: This answer is based on code found here.

Community
  • 1
  • 1
Sean
  • 60,939
  • 11
  • 97
  • 136
  • 2
    Reflection should be an absolute last resort though; it's generally terrible in terms of type safety and performance. I would much rather do what @TheInnerLight said and use FParsec's dedicated functions. – Tarmil May 12 '17 at 07:47
  • 1
    @Tarmil Wholly agree with you Tarmill - just given the way I phrased the question Sean's answer's correct. – Koenig Lear Jul 14 '17 at 10:36