Chiami i tipi "simili", ma sono solo simili a te. Il compilatore non sa nulla di questa somiglianza, quindi o hai bisogno del compilatore per apprenderlo o per alleviare in qualche modo. Ecco alcune possibili soluzioni che prenderei in considerazione in questa situazione:
Morde il proiettile e elenca tutti i casi (ovvero quello rapido)
Prima di considerare le possibilità più coinvolgenti, ricorda che puoi sempre semplicemente elencare tutti i casi. Ci sono% casi dim * n
lì, quindi dovrebbe essere gestibile fino a 4 o forse 5 casi ciascuno se si strappa abbastanza.
In F # hai qualcosa chiamato pattern attivi che ti consente di definire un modo personalizzato per dividere il dominio con cui stai confrontando. Puoi usarlo per incapsulare la parte di corrispondenza dettagliata e riutilizzarla nelle corrispondenze successive. Scala ha estrattori che presumibilmente sono paragonabili ai modelli attivi.
Certamente questo non si adatta bene.
Aggiungi il tipo mancante (ovvero quello corretto)
L'osservazione che i tipi MetadataX
e DataX
sono apparentemente simili, ma il compilatore non ne sa nulla, implicherebbe che ci sia un tipo intermedio che manca all'immagine. È possibile introdurre quel tipo e farà semplicemente scomparire l'intero problema di corrispondenza.
type DataSet =
| DataSet1 of Metadata1 * Data1
| DataSet2 of Metadata2 * Data2
| DataSet3 of Metadata3 * Data3
Naturalmente, ciò che rende le cose più facili dipende da come costruirai le istanze di quel tipo. Immagino che potresti avere tutto il Metadatas
a portata di mano, ed è solo questione di ottenere quello giusto per il Data
che ti viene consegnato, ma avrei davvero bisogno di saperne di più dell'immagine qui.
Suddividi la corrispondenza (ovvero quella pragmatica)
Se ci sono troppi casi da gestire e non è possibile aggiungere il tipo mancante per qualche motivo, è sempre possibile ristrutturare l'espressione della corrispondenza. Avresti bisogno di estrarre una logica comune nelle funzioni e perderai un po 'di leggibilità, ma almeno ti aggiri nell'esplosione combinatoria dei casi e continui a mantenere gli avvertimenti "caso non gestito". Il codice è in F #, ma puoi trattarlo come pseudo-codice (meno verboso di Scala comunque):
match data with
| Data1 d ->
match metadata with
| Metadata1 md -> (* the proper logic goes here *)
| other -> (* handle the unmatched types here using a common function *)
| Data2 d ->
match metadata with
| Metadata2 md -> (* the proper logic goes here *)
| other -> (* handle the unmatched types here using a common function *)
(...)
Con questo, hai ancora una corrispondenza esauriente sui casi di Data
, e le corrispondenze annidate danno solo un leggero sovraccarico a ciascun caso.
Immagino che potrebbe essere reso ancora più bello rifasando le corrispondenze annidate in funzioni che scelgono una delle due continuazioni a seconda di un controllo booleano se i tipi Data e Metadata si adattano insieme.