Matching tuple elements with "as" pattern

Viewed 53

I'd like to convert tuple of two elements having the same type to a list. Code looks simple as this:

let toList (tuple: 'a * 'a): 'a list =
    match tuple with
    | (_ as fst, _ as snd) -> [fst; snd]

But somehow type of snd is 'a * 'a, so it seems like instead of binding second element of tuple to a variable the whole tuple is bound instead. Is it a bug in compiler or am I missing sth?

Actual code is more complicated, so the idea is not to rewrite the piece provided, but to understand what is wrong with the as usage here. I'd expect that as should go after the tuple to bound it as a whole, like this | (_ as fst, _ as snd) as tuple

2 Answers

The correct syntactic form of the "as" pattern is

pat as ident

This defines ident to be equal to the pattern input and matches the pattern input against pat.

For your code this means

let toList (tuple: 'a * 'a): 'a list =
    match tuple with
    | (fst, snd) -> [fst; snd]

where (fst, snd) is a tuple-pattern.

See F# language spec section 7.3 for full details of the "as" pattern.

For practical purposes @nilekirk's answer is better: you don't need as in this particular case at all.

But if you're wondering why snd has this type for learning purposes, here's an explanation.


Your pattern is compiled like this:

| ((_ as fst, _) as snd) ->

That is, tupling binds stronger than pattern aliasing.

If you want each as to apply to a single element of the tuple, you need to explicitly tell the compiler how to parenthesize them:

| ((_ as fst), (_ as snd)) ->

And incidentally, in F# tuples don't have to be in parens, so the outer parens are not necessary:

| (_ as fst), (_ as snd) ->
Related