问题
Let's say I write this code :
# type t = A of int * int
  let f = function A (i1, i2) -> print_int i1;;
type t = A of int * int
val f : t -> unit = <fun>
Perfect, it works.
Now, let's say I have this wonderful function :
# let print_couple (i1, i2) = print_int i1; print_int i2;;
val print_couple : int * int -> unit = <fun>
So, as you expect, I'd like to write the following
# let f = function A (_ as c) -> print_couple c;;
Well, I can't
Error: The constructor A expects 2 argument(s),
       but is applied here to 1 argument(s)
I wondered, is it because of the _ or the parenthesis (I seriously had doubts about that but I wanted to be exhaustive) ?
# let f = function A _ -> failwith "Fight me"
  let g = function A (_) -> failwith "1o1";;
val f : t -> 'a = <fun>
val g : t -> 'a = <fun>
No, it isn't...
Oh, maybe I have to show the compiler I know I have two arguments :
# let f = function A ((_, _) as c) -> print_couple c;;
Error: The constructor A expects 2 argument(s), 
       but is applied here to 1 argument(s)
But... If I write
# let f = function A (_, _) -> failwith "Puppey style";;
It works. Then why, since the compiler knows that I'm expecting a couple and I'm even trying to give it to him it keeps failing ? Is it that by writing A (_ as c) I'm naming, no matter what, the first argument ? It's strange, isn't it ?
I mean, if I write
# let rec f = function
    | [] -> ()
    | hd :: tl -> print_couple hd; f tl;;
val f : (int * int) list -> unit = <fun>
The compiler won't bother me about this list being an association list or an integer list ? Then is it strange from me to expect the same behaviour from
 # match a with
    | A c | A (_ as c) | A ((_, _) as c) -> ()
?
回答1:
It's a quirk of OCaml that a constructor like your definition of A takes what syntactically looks like a pair, but is not a pair.
# type t = A of int * int;;
type t = A of int * int
# A (3, 4);;
- : t = A (3, 4)
# let z = (3, 4) in A z;;
Error: The constructor A expects 2 argument(s),
       but is applied here to 1 argument(s)
If you define the constructor as actually taking a pair, you can supply a pair:
# type u = B of (int * int);;
type u = B of (int * int)
# B (3, 4);;
- : u = B (3, 4)
# let z = (3, 4) in B z;;
- : u = B (3, 4)
This is somewhat confusing, but it's just the way OCaml works. You need to supply specifically parenthesized arguments to a constructor like A.
It's also a little surprising that you don't need to supply explicit parentheses when matching against _:
# let A _ = A (4, 5);;
# 
(This is only useful as part of a larger pattern, of course.)
回答2:
Strictly speaking, when you declare A of int * int, A expects two int arguments and not a single argument consisting in a pair of int. _ is a placeholder for only one argument, hence the error message you see when you write A (_ as c) (or A _). There is no way (short of using dark magic I won't describe here) to somehow implicitely transform the two arguments of A into a pair: you have to resort to match x with A (x,y) -> x,y.
An alternative is to declare your constructor so that it takes a pair, like in the code below. Be aware that this is less efficient though (you need two indirections to access the arguments of A, one to retrieve the couple, and one to retrieve its components):
type t = A of (int * int)
let print_couple (i1, i2) = print_int i1; print_int i2
let f = function A c -> print_couple c
来源:https://stackoverflow.com/questions/40002575/ocaml-as-keyword-in-pattern-matching-behaving-strangely