2009-11-17 23 views
19

Ho fatto un po 'di programmazione OCaml ultimamente per imparare la lingua e per avere più familiarità con la programmazione funzionale. Recentemente, ho iniziato a pensare che mi piacerebbe essere in grado di estendere un tipo esistente (sia costruito in-o uno dei miei), per esempio:Estensione di un tipo esistente in OCaml

type bexp = 
    And of bexp * bexp 
| Or of bexp * bexp 
| Xor of bexp * bexp 
| Not of bexp;; 

Ora diciamo che voglio aggiungere una variante Nop per questo tipo, ma solo per l'uso in un nuovo tipo - tipo di ereditarietà. Ehi, questi dovrebbero essere tipi di dati algebrici, giusto? Allora perché non qualcosa di simile:

type nbexp = bexp | Nop nbexp ;; 

... ma questo non è valido OCaml, dà un errore di sintassi. Fondamentalmente, quello che sto cercando di fare è dire che voglio che nbexp includa tutto ciò che include bexp e aggiunga anche un Nop. Suppongo che questo non sia possibile perché, se per esempio hai usato il costruttore And non ci sarebbe stato modo di determinare se fosse un tipo bexp o un tipo nbexp. (Credo che il costruttore Nop prendendo una nbexp può anche essere problematico.)

Quindi non v'è alcun modo per fare qualcosa di simile in OCaml? E questo è il genere di cosa che è fattibile in Haskell (con i typeclass, forse)?

+1

Forse di interesse: https://sites.google.com/site/ocamlopen/ –

risposta

19

Una soluzione interessante è quella di utilizzare variante polimorfica:

type bexp = 
[ `And of bexp * bexp 
| `Or of bexp * bexp 
| `Xor of bexp * bexp 
| `Not of bexp ];; 

type nbexp = [ bexp | `Nop of nbexp ];; 

noti che varianti polimorfiche sono più difficili di quelle normali, ma consentono estensione di tipo.

Un interessante esempio di valutazione dell'espressione, con estensione, utilizzando variante polimorfica può essere trovato in una prova directory della sorgente ocaml, vedere l'aggiornamento svn

+1

Ho sentito parlare di questi, ma non hanno ottenuto intorno davvero ad usare loro. Questo mi dà una buona ragione pratica per saperne di più su di loro. Grazie. – aneccodeal

4

Ehi, questi dovrebbero essere tipi di dati algebrici, giusto?

Diritto. E algebraic data types sono costruiti da unioni e prodotti taggati (noti anche come discriminati). Quello che vuoi è solo un sindacato (non taggato), che è non un tipo di dati algebrico e non è supportato da Haskell. OCaml ha varianti polimorfiche (vedi altre risposte).

Typed Scheme supporta sindacati non con tag, quindi si consiglia di check it out.

4

Come lei stesso in modo corretto supporre, questo non è possibile in tipi algebrici. Sono d'accordo con il suggerimento di Apocalisp che si può semplicemente racchiudere la parte "ereditata" di nbexp in un costruttore proprio.

Vorrei aggiungere che la mancanza di ereditarietà di tipi algebrici fa parte della loro magnificenza. Ciò significa che un'espressione come And(foo, bar) viene digitata in modo non ambiguo e che il casting (su o giù) non ha alcun ruolo da riprodurre nel sistema di tipi. Ciò offre maggiore sicurezza e maggiore chiarezza. Questo naturalmente richiede del programmatore che lui/lei gestire esplicitamente i casi in cui s/vuole interagire con i bexp parti nbexp, ma se ci pensate, è così che la maggiore sicurezza e la chiarezza si realizza nella pratica.