2017-07-04 5 views
0

Ich habe von this question gelernt, dass es möglich ist, Mustererkennung mit Datensätzen zu verwenden. Ich habe jedoch bemerkt, dass ich Probleme habe, verschiedene Arten von Datensätzen zu finden.Ambiguität mit Musterabgleich Datensätze

Mein Ziel in diesem Beispiel ist es, in der Lage zu sein, zwischen verschiedenen Datensätzen zu unterscheiden. Mir wurde ein Datensatz gegeben, bei dem ich nicht ganz sicher bin, um welchen Typ es sich handelt, und ich versuche, es mithilfe des Mustervergleichs herauszufinden.

Hier ist ein vereinfachtes Beispiel:

module IceCream = struct 
    type t = { 
    temperature: float; 
    toppings: string list; 
    } 
end 

module Candy = struct 
    type t = { 
    flavour: string; 
    colour: string; 
    volume: int; 
    } 
end 


(* Could be Candy or IceCream *) 
let example = 
    { Candy. 
    flavour = "mint"; 
    colour = "green"; 
    volume = 10 } 

let printFavoriteTreat treat = match treat with 
    | { Candy. 
     flavour = "mint"; 
     colour; 
     volume } -> "It's Candy" 
    | { IceCream. 
     temperature; 
     toppings } -> "It's IceCream" 


let() = printFavoriteTreat example 

Wenn ich versuche, diese Datei zu erstellen, erhalte ich:

Error: The field IceCream.temperature belongs to the record type IceCream.t 
     but a field was expected belonging to the record type Candy.t 

ist so etwas wie dies möglich machen?

+0

Pattern-Matching für verschiedene Typen ist nicht möglich, es sei denn, sie sind in einen Summentyp eingebettet (auch Variantentyp, algebraischer Datentyp, diskriminierte Union). – didierc

Antwort

3

Ich habe eine Aufzeichnung, dass ich nicht ganz sicher bin, welcher Typ es ist, und ich versuche es herauszufinden, Mustererkennung zu verwenden.

Das ist nicht möglich. Typen existieren nur zur Kompilierzeit, also ist es nicht möglich, zu prüfen, welcher Typ zur Laufzeit ist.

Mit anderen Worten, in einem gültigen Programm können Sie einen Typ Annotation auf jeden Ausdruck setzen (in den meisten Fällen müssen Sie dies jedoch nicht tun, dank Typ-Inferenz). Wenn Sie das nicht können, sollten Sie Ihr Programm anders gestalten, z. B. mit einem Summentyp, wie andere vorgeschlagen haben. In diesem Fall haben beide Werte denselben Typ (zur Kompilierungszeit), aber einen anderen Konstruktor (zur Laufzeit).

1

Sie versuchen, zu verschiedenen Typen zu passen, ohne Variantentypen zu verwenden.

Die Modul-Syntax, die Sie verwenden, kann nicht helfen, da das Modul nur den Code strukturiert. Sie könnten die folgenden Typen definiert haben:

type a = { 
    temperature: float; 
    toppings: string list; 
    } 

type b = { 
    flavour: string; 
    colour: string; 
    volume: int; 
    } 

Aber die Ergebnisse wären die gleichen.

Die Art und Weise Variantentypen eindeutig zu machen (oder Union-Typen, die in dem Beispiel nicht unten beschrieben) verwenden:

let printFavoriteTreat treat = match treat with 
    | `A{ Candy. 
     flavour = "mint"; 
     colour; 
     volume } -> "It's Candy" 
    | `B { IceCream. 
     temperature; 
     toppings } -> "It's IceCream" 
;; 

Und

let() = printFavoriteTreat (`A example) 
+0

Sie sollten wahrscheinlich Candy anstelle von A und Icecream anstelle von B verwenden. Und erklären Sie, warum eine polymorphe Variante (+ '' _ _ -> "Ich weiß nicht, dass behandeln" ') statt einer normalen. –

3

Die Antwort von Pierre vorgesehen ist groß, aber das Beispiel nicht so sehr. (Ich habe immer Beispiele gehasst namens a, b ...)

So, wie Pierre schon sagt, Sie Typen wie folgt definieren könnte:

type ice_cream = { 
    temperature: float; 
    toppings: string 
} 

type candy = { 
    flavor: string; 
    color: string; 
    volume: int 
} 

Dann Sie einen Typ treat als definieren variant dieser beiden Typen:

type treat = 
| Candy of candy 
| IceCream of ice_cream 

Dann Mustervergleich unter Verwendung von:

let print_favorite_treat = function 
| Candy _ -> print_endline "You love candy!" 
| IceCream _ -> print_endline "You love ice cream!" 
+0

groß, das ist die Verwendung der Union-Typ;) –

+0

Die Tatsache, dass die Funktion 'print_favorite_treat' heißt, ist ein großer Hinweis, dass eine Art von' treat' Typ benötigt wird. :) – RichouHunter

+0

Ah Ich hatte gehofft, ich könnte Varianten vermeiden, aber es sieht so aus, als ob du die Datensätze nicht so wie ich es versucht abgleichen könntest, danke für die Antwort :) –

Verwandte Themen