Equivalent of fst and snd for F# struct tuples?

Viewed 360

If I am using reference tuples, this compiles:

let plot(x: int, y: int) = ()
let point = 3, 4
plot(fst point, snd point)

However, if I am using struct tuples...

let plot(x: int, y: int) = ()
let point = struct (3, 4)
plot(fst point, snd point)

... I get the compiler error, One tuple type is a struct tuple, the other is a reference tuple

What should I do?

3 Answers

There's a ToTuple() extension method in System.TupleExtensions for ValueTuple<T1, T2...>.

You could just call:

plot (point.ToTuple())

As for fst, snd, they're bound to System.Tuple<>, so maybe you could define an alternative:

let fstv struct (a,_) =  a
let sndv struct (_,b) =  b

In F# 4.7, you must add another line to decompose the tuple.

let plot(x: int, y: int) = ()
let point = struct (3, 4)
let struct (x, y) = point
plot(x, y)

You can declare new functions that work on struct tuples:

let fstv (struct (a, _)) = a
let sndv (struct (_, b)) = b

Usage:

let plot(x: int, y: int) = ()
let point = struct (3, 4)
plot(fstv point, sndv point)

If you want to get clever, you can use SRTP to make new fst and snd functions that work with both struct tuples and regular tuples:

type PairDispatcher = 
  | PairDispatcher with
    static member inline ($) (PairDispatcher,        (a, b)) = fun f -> f a b
    static member inline ($) (PairDispatcher, struct (a, b)) = fun f -> f a b
  
let inline fst x = (PairDispatcher $ x) (fun a _ -> a)
let inline snd x = (PairDispatcher $ x) (fun _ b -> b)

(Taken from http://www.fssnip.net/7TT/title/Generic-fst-and-snd-functions)

Then usage is:

let plot(x: int, y: int) = ()
let point = struct (3, 4)
plot(fst point, snd point)

I think on balance I would prefer to declare new functions.

Related