Как я могу разложить дискриминационный союз, который является типом?

Предположим, у меня есть следующее (основное и немного бессмысленное) F#...

type Point = Point of int * int
type MyUnion =
    | MyInt of int
    | MyString of string
    | MyTwoStrings of string * string
    | MyPoint of Point

... тогда я могу написать такую ​​функцию...

let MyUnionType myunion =
  match myunion with
  | MyInt n -> printfn "You gave me an Int (%d)" n
  | MyString s -> printfn "You gave me a string (%s)" s
  | MyTwoStrings (s1, s2) -> printfn "You gave me two strings (\"%s\", \"%s\")" s1 s2
  // Missing case here...

Это отлично работает для первых трех вариантов MyUnionType но я не могу понять, как написать предложение, чтобы соответствовать, когда это MyPoint

Я попробовал следующее, похожее на MyTwoStrings дело...

| MyPoint (p1, p2) -> printfn "You gave me a point (%d, %d)" p1 p2

... но это дает ошибку компилятора о том, что (p1, p2) должен был иметь тип Point но имеет тип 'a * 'b

Я попробовал следующее...

| MyPoint p -> printfn "You gave me a point (%A)" p

.. который работает, но не дает мне доступ к двум int значения в Point

Как мне добраться до двух int значения в Point?

2 ответа

Решение

type Point = Point of int * int является единичным дискриминационным объединением, а не просто кортежем.

Вы конструируете это как let p = Point(0, 0)так что вам нужно деконструировать его аналогичным образом. Ваш последний пример - хорошая отправная точка: | MyPoint p -> ... связывает Point значение для p, так что вы можете позже деконструировать его:

| MyPoint p ->
    let (Point (p1, p2)) = p
    printfn "You gave me a point (%i, %i)" p1 p2

или вы можете объединить деконструкцию в match сам:

| MyPoint (Point (p1, p2)) -> printfn "You gave me a point (%i, %i)" p1 p2

Ваш тип Point имеет точно такой же характер, как ваш тип MyUnion, Единственная разница в том, что Point имеет один конструктор, но MyUnion имеет несколько Вот и все.

Тот факт, что PointКонструктор имеет то же имя, что и сам тип, совершенно не имеет значения. Имена типов и имена конструкторов находятся в разных пространствах имен. Они могут быть одинаковыми или разными, это ничего не меняет.

Итак, способ вывести содержимое вашего Point тип будет точно таким же, как с MyUnion, например:

let sumCoords p = match p with
    | Point (x,y) = x + y

И затем, этот шаблон также может быть вложен в другой шаблон:

let MyUnionType myunion =
      match myunion with
      | MyInt n -> printfn "You gave me an Int (%d)" n
      | MyString s -> printfn "You gave me a string (%s)" s
      | MyTwoStrings (s1, s2) -> printfn "You gave me two strings (\"%s\", \"%s\")" s1 s2
      | MyPoint (Point (x,y)) -> printfn "You gave me a point (%d, %d)" x y
Другие вопросы по тегам