2012-04-14 12 views
13

Sto definendo un parser osservabile/reattivo monadico. Questo comportamento si comporta in modo abbastanza diverso da un normale parser in quanto è una query continua. Il tipo di fondo è:Scopo di un'unione discriminata a caso singolo

IObservable<'a> -> IObservable<'b> 

Guardando varie implementazioni di parser in linguaggi funzionali, sembra come se il modo più appropriato per definire le cose è un singolo caso un'unione discriminata:

type Pattern<'a,'b> = Pattern of (IObservable<'a> -> IObservable<'b>) 

il che significa che quindi necessario estrarre la funzione di fondo di usarlo:

let find (Pattern p) = p 

la domanda è: questo solo per convenzione, o per scopi di proroga al più tardi, o è la è un motivo per farlo anche se la definizione non cambia mai?

Bonus domanda: Se è solo per una firma di tipo più conveniente, perché non basta usare un tipo alias:

type Pattern<'a,'b> = IObservable<'a> -> IObservable<'b> 

ho avanzato una piuttosto un modo attraverso questo, e non ho trovato un caso in cui la componibilità è influenzata dal non utilizzo del DU.

risposta

14

compilatore F # non conserva informazioni sul tipo di abbreviazione, in modo da non beneficiare di inferenza di tipo a tutti. La firma del tipo può essere intesa come specifica del programma; lasciare che il correttore di tipi faccia il loro lavoro è un buon modo per garantire la correttezza dei tuoi programmi.

È necessario specificare esplicitamente il tipo di annotazione ovunque nel caso di tipo alias:

type Vector = float * float 

// val add : float * float -> float * float -> Vector 
let add ((x1, y1): Vector) ((x2, y2): Vector): Vector = (x1 + y1, x2 + y2) 

ma non ti dà la trasparenza come l'utilizzo a valle:

type Vector = V of float * float 

// val add : Vector -> Vector -> Vector 
let add (V(x1, y1)) (V(x2, y2)) = V(x1 + y1, x2 + y2) 

Nei programmi complessi di tipo chiare firme anzi rendono più facile mantenere la componibilità.

Non solo è più semplice aggiungere più casi a DU a singolo caso, ma è anche più facile estendere DU con metodi membro e statici. Un esempio è che sovrascrivi spesso ToString() per una bella stampa.

+0

Grazie, è in realtà una ragione abbastanza concreta. Sicuramente non voglio digitare 'IObservable <'a> -> IObservable <'b>' ovunque invece di 'Modello <'a,'b>'. – yamen

+1

Un follow-up molte lune più tardi. Ho finito per aggiungere un secondo caso al sindacato, e quindi l'universo è in equilibrio. – yamen

0

Da quello che ho capito, il tipo di unione discriminato con un singolo caso è lì per fornire un nome semanticamente rilevante per il dominio del problema, per un tipo di back-end altrimenti generico il cui nome è 'stringa'.

Si tratta di una correzione delle perdite astrazione luce per la semantica, e solo quello, per quanto ne so

+0

Non penso sia vero. Questo è un alias di tipo. Un unione discriminata con un singolo caso è una classe completa, e in questo caso si tratta di una funzione (o delegato in C# talk). – yamen

+0

davvero. ma non conosco altri usi oltre a quello ... anche, si noti che è possibile aggiungere alcuni metodi ai tipi di unione. – nicolas