QNA > Q > Quali Sono Le Buone Applicazioni Dei Tipi Fantasma?

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:

  1. type utf8 = Utf8 of string 
  2. type iso88591 = Iso88591 of string 
  3.  
  4. let string_of_utf8 (Utf8 s) = s 
  5. 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:

  1. let concat_utf8 (Utf8 a) (Utf8 b) = Utf8 (a ^ b) 
  2. 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:

  1. (* polymorphic type *) 
  2. type 'a text 
  3. (* implemented as: type 'a text = string *) 
  4.  
  5. (* artificial abstract types (we never create a value of these types) *) 
  6. type utf8 
  7. type iso88591 
  8.  
  9. (* safe, polymorphic operations *) 
  10. val to_string : 'a text -> string 
  11. val concat : 'a text -> 'a text -> 'a text 
  12. (* This guarantees that the two input strings 
  13. have the same type, i.e. the same encoding. 
  14. Note that actual data cannot have a polymorphic type 
  15. because we only provide the creation functions below. 
  16. The only two choices are utf8 text and iso88591 text. 
  17. *) 
  18.  
  19. (* validation functions *) 
  20. val utf8_of_string : string -> utf8 text 
  21. val iso88591_of_string : string -> iso88591 text 
  22.  
  23. (* identity functions *) 
  24. val string_of_utf8 : utf8 text -> string 
  25. 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.

Di Churchill

È facile programmare buone applicazioni usando Visual Studios e Unity? :: Qual è la migliore applicazione da scaricare nel tuo smartphone?
Link utili