2012-04-24 7 views
6

Dato un esempio tipo di dati con il record sintassi:pattern matching vs funzione sintassi record per tipo di dati estrazione campo

data VmInfo = VmInfo {infoVid :: String 
        ,infoIndex :: Int 
        ,infoPid :: Int 
        ,infoExe :: String 
        } deriving (Show) 

e (vmInfo :: String -> VmInfo) funzione che genera e restituisce la struttura di dati sopra dato nome vm come stringa.

posso vedere due metodi per estrarre le singole parti del tipo di dati VmInfo.

(VmInfo vid _ _ _) <- vmInfo vm 

che è solo un pattern match. E ...

vid <- infoVid <$> vmInfo vm 

utilizzando le funzioni generate dal compilatore della sintassi del record.

La domanda è semplice: qual è il metodo preferito?

Importo-of-digitando saggi sono la stessa cosa quindi non vedo per la velocità e la correttezza delle migliori pratiche /.

Suppongo che il pattern matching sarebbe più veloce, ma allora qual è il punto di sintassi disco?

Grazie.

+1

Credo che la sintassi del record venga trasformata nella versione di corrispondenza del modello dal compilatore, quindi non ci sarà alcuna differenza di velocità. – ricochet1k

risposta

8

Questi non sono equivalenti semanticamente. sguardo

Let al primo esempio:

(VmInfo vid _ _ _) <- vmInfo vm 

Questo esegue un pattern match nell'operazione vincolante. Ci sono due risultati di questo. Il primo è che viene valutata la funzione di costruzione del risultato dell'azione vmInfo vm. Ciò significa che se vmInfo si è conclusa con una linea come return undefined, l'eccezione generata valutando undefined sarebbe successo a questo pattern match, non un uso successivo di vid. Il secondo è che se la corrispondenza del modello viene confutata (la corrispondenza del modello non corrisponde al valore), l'istanza fail della monade verrà chiamata con il testo dell'errore di corrispondenza del modello. Ciò non è possibile in questo caso, ma è generalmente possibile quando il pattern corrisponde a un costruttore in un binding.

Ora, al prossimo esempio:

vid <- infoVid <$> vmInfo vm 

nella definizione di <$>, questo sarà completamente pigri nel valore restituito dall'azione (non gli effetti). Se vmInfo termina con return undefined, non si otterrà l'eccezione dalla valutazione di undefined finché non si è fatto qualcosa che utilizzava il valore di vid. Inoltre, se infoVoid avesse la possibilità di lanciare eccezioni, non finirebbe per accadere fino all'utilizzo di vid, caso migliore.

È interessante notare che queste differenze sono presenti solo nel l'ambito di una legatura monadica. Se vmInfo era puro e si stava legando il nome vid all'interno di un'espressione let o where, si generava un codice identico.

In tal caso, che quello che si desidera utilizzare è interamente a voi. Entrambi sono idiomatici di Haskell. In genere, le persone scelgono ciò che sembra migliore nel contesto in cui lavorano.

I motivi principali per cui le funzioni di accesso vengono utilizzate sono la brevità quando il record ha così tanti campi che una corrispondenza di pattern è enorme e poiché sono funzioni effettive - possono essere passati a qualsiasi funzione di ordine superiore in cui si inserisce il loro tipo. Non è possibile passare attorno a corrispondenze di pattern come costrutto distinto.

+6

Un altro motivo per utilizzare gli accessor sulla corrispondenza dei pattern è rendere il codice un po 'più robusto rispetto alla modifica della struttura dei dati man mano che il programma viene mantenuto. Se si modifica una struttura di dati praticamente in qualsiasi modo, in genere tutte le corrispondenze di modello non verranno compilate. Se hai a che fare solo con un piccolo numero di campi alla volta in un tipo con molti campi, quindi usare gli accessor significa che le modifiche alla struttura dei dati hanno buone possibilità di influenzare solo i luoghi che usano i campi che hai aggiunto/rimosso/modificato. – Ben

+6

@Ben Per ottenere i vantaggi di entrambi, 'VmInfo {infoVid = vid} <- vmInfo vm'. –