jeff
jeff

Reputation: 1098

How can I treat a type that is essentially a tuple as a tuple in F#

Ok, so let's say I have a type defined like so:

type Foo = 
    | Bar of (SomeType * SomeType * SomeType * SomeType)
    | ...(other defs)

so I have a Bar, that is basically a tuple of 4 SomeTypes. I want to access individual members of the tuple. I tried this:

let Bar (one, two, three, four) = someBar

But when I try to refer to one, or two later on in the function it says that "the value or constructor is not defined" So it is not treating the assignment as expected. What is the correct way to do this?

Also, if i try:

let one,two,three,four = someBar

It complains: someBar was expected to have type 'a*'b*'c*'d but here has type Foo

thanks,

Upvotes: 4

Views: 188

Answers (2)

Stephen Swensen
Stephen Swensen

Reputation: 22307

Given

type Foo = 
    | Bar of (int * int * int * int)
    | Bar2 of string

let x = Bar(1,2,3,4)

let Bar(y1,y2,y3,y4) = x

the last let binding is interpreted as a function, Bar : 'a * 'b * 'c * 'd -> Foo. The function name is throwing you off, since it is the same as your union case, but it's the same as if you had defined let some_func_takes_a_tuple_and_returns_x (y1,y2,y3,y4) = x.

I think you may have to be a little more verbose:

let y1,y2,y3,y4 =
    match x with
    | Bar(y1,y2,y3,y4) -> y1,y2,y3,y4

Which is fair enough, since unlike tuple decomposition let bindings, decomposing Bar here is dangerous because the match is incomplete (x could actually be some other Foo case, like Bar2).

Edit

@kvb knows the secret to making this work as you expect!

Upvotes: 1

kvb
kvb

Reputation: 55195

You just need to add another set of parentheses:

let (Bar(one,two,three,four)) = someBar

As Stephen points out, without the additional parens the compiler treats this line of code as the definition of a new function called Bar. He is also right that pattern matching would probably be more appropriate if there are other cases in the discriminated union.

Upvotes: 6

Related Questions