Quali sono le buone applicazioni dei tipi fantasma?
I tipi fantasma sono utili quando si vuole trattare con diversi tipi di dati che hanno la stessa rappresentazione ma non devono essere mescolati. I tipi fantasma sono diversi tipi astratti per lo stesso tipo concreto. Poiché sono specializzazioni (sottotipi) di un tipo più generale, il vantaggio è quello di scrivere una serie di funzioni di utilità che lavorano per il tipo generale (funzioni polimorfiche). Un'interfaccia di modulo scritta correttamente garantisce che i dati di due tipi diversi non vengano combinati e che gli oggetti di ogni tipo fantasma verifichino sempre un insieme specifico di proprietà.
Un esempio è l'uso delle stringhe per rappresentare il testo in diverse codifiche. Potremmo provare ad usare varianti di OCaml (tipi di dati algebrici) per questo:
- type utf8 = Utf8 of string
- type iso88591 = Iso88591 of string
- let string_of_utf8 (Utf8 s) = s
- let string_of_iso88591 (Iso88591 s) = s
The extra wrapping is slightly inefficient but usually not a problem. Now the real problem is to write a single function that would do something with strings regardless of their encoding, such as concatenation.
For our example, we would have to write two different implementations of concat:
- let concat_utf8 (Utf8 a) (Utf8 b) = Utf8 (a ^ b)
- let concat_iso88591 (Iso88591 a) (Iso88591 b) = Iso88591 (a ^ b)
Apparently this is not convenient.
Actually it is only a problem if you have a lot of these (number of subtypes times number of generic functions).
Now phantom types will allow us to use the generic and concrete string type for internal purposes. We only write one concat function, as follows:
let concat = ( ^ )
The trick is to define the following interface:
- (* polymorphic type *)
- type 'a text
- (* implemented as: type 'a text = string *)
- (* artificial abstract types (we never create a value of these types) *)
- type utf8
- type iso88591
- (* safe, polymorphic operations *)
- val to_string : 'a text -> string
- val concat : 'a text -> 'a text -> 'a text
- (* This guarantees that the two input strings
- have the same type, i.e. the same encoding.
- Note that actual data cannot have a polymorphic type
- because we only provide the creation functions below.
- The only two choices are utf8 text and iso88591 text.
- *)
- (* validation functions *)
- val utf8_of_string : string -> utf8 text
- val iso88591_of_string : string -> iso88591 text
- (* identity functions *)
- val string_of_utf8 : utf8 text -> string
- val string_of_iso88591 : iso88591 text -> string
Note that I personally have used phantom types in useful software only once, right after discovering the trick. L'ho usato per ints e stringhe usate come identificatori unici all'interno di strutture dati complesse dove diversi tipi di ID erano spesso passati come argomento alla stessa funzione. Il vantaggio di farlo, al di là di qualche divertimento personale, era limitato perché solo due funzioni, "create" e "incr" erano effettivamente usate sul tipo polimorfo.
Ci sono casi d'uso leggermente diversi di tipi fantasma, ma il problema in generale è che rende i tipi innaturali, perché il parametro del tipo non corrisponde a valori fisici come avviene normalmente. Questo va a scapito della leggibilità del codice. I rimedi sono:
- utilizzando semplici tipi astratti senza parametri e copiando i binding alle poche funzioni polimorfiche (ad esempio, let concat_ut8 = ( ^ );; let concat_iso88591 = ( ^ )
- utilizzando lo stesso tipo ovunque. Per le codifiche charset, convertiamo i dati di input in UTF-8 una volta e assumiamo che il codice base usi esclusivamente UTF-8.
- mantenendo il tipo sottostante (ad esempio stringa), usando sempre nomi di variabili che hanno il nome del tipo (ad esempio utf8 o iso88591) e usando argomenti di funzione etichettati per evitare di scambiarli per sbaglio. Questa è la soluzione che uso per i nomi dei file.
Articoli simili
- In Outlander, quali sono le teorie riguardanti il fantasma?
- Quando ha visto per la prima volta La minaccia fantasma, a che punto ha pensato tra sé e sé: "Questo potrebbe essere davvero brutto"?
- Perché un'immagine che è stata sul mio telefono ha un fantasma di essa dopo il cambio di cornice? Ho un Note 20 Ultra con 120 Hz su.
- Come bloccare i numeri fantasma dal chiamare il mio telefono