Casa > Q > Quais São As Boas Aplicações Dos Tipos Fantasmas?

Quais são as boas aplicações dos tipos fantasmas?

Tipos fantasmas são úteis quando você quer lidar com diferentes tipos de dados que têm a mesma representação mas não devem ser misturados. Os tipos fantasmas são diferentes tipos abstratos para o mesmo tipo concreto. Como são especializações (subtipos) de tipo mais geral, a vantagem é escrever uma série de funções utilitárias que funcionam para o tipo geral (funções polimórficas). Uma interface de módulo devidamente escrita garante que dados de dois tipos diferentes won't sejam combinados e que objetos de cada tipo fantasma sempre verifiquem um conjunto específico de propriedades.

Um exemplo é o uso de strings para representar texto em diferentes codificações. Nós poderíamos tentar usar variantes OCaml (tipos de dados algébricos) para isso:

  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. Utilizei-o para ints e strings utilizados como identificadores únicos dentro de estruturas de dados complexas onde diferentes tipos de IDs eram frequentemente passados como argumento para a mesma função. A vantagem de fazer isso, além de alguma diversão pessoal, foi limitada porque apenas duas funções, "create" e "incr" foram realmente usadas no tipo polimórfico.

Existem casos de uso ligeiramente diferentes de tipos fantasmas, mas o problema em geral é que isso torna os tipos não naturais, porque o parâmetro do tipo não corresponde aos valores físicos como é normalmente o caso. Ele vai no caminho da legibilidade do código. As soluções são:

  • usando tipos abstratos sem parâmetros e colando as ligações para as poucas funções polimórficas (por exemplo, let concat_ut8 = ( ^ ); let concat_iso88591 = ( ^ ) )
  • li>usando o mesmo tipo em todos os lugares. Para codificações de charset, convertemos os dados de entrada para UTF-8 uma vez e assumimos que a base de código usa exclusivamente UTF-8.
  • manter o tipo subjacente (por exemplo, string), usando sempre nomes de variáveis que têm o nome do tipo (por exemplo, utf8 ou iso88591) e usando argumentos de funções etiquetadas para evitar a troca acidental. Esta é a solução que eu uso para nomes de arquivos.

De Forsta

Quais são algumas boas ferramentas para monitoramento e análise de aplicações Java e JVM? :: É fácil programar boas aplicações usando Visual Studios e Unity?