2015-01-14 19 views
26

Devo imparare Haskell per l'università e quindi sto usando learnyouahaskell.com per l'inizio.
Ho sempre usato le lingue imperative, quindi ho deciso di praticare Haskell codificando molto più di quanto avrei fatto per altre lingue.
ho iniziato a implementare diverse funzioni per lavorare con le liste, come head, tail, init, ...
Ad un certo punto ho guardato le implementazioni di queste funzioni per confrontare al mio e mi sono imbattuto la funzione nullo definita in List.lhs . implementazioneImplementazione della funzione nulla

di nulla:

-- | Test whether a list is empty. 
null     :: [a] -> Bool 
null []     = True 
null (_:_)    = False 

mia implementazione:

mNull :: [a] -> Bool 
mNull []  = True 
mNull _   = False 

So che ci sono domande stupide, anche per tali domande semplici :)
Quindi la mia domanda è perché gli usi implementazione originale (_:_) anziché solo _?
C'è qualche vantaggio nell'uso di (_:_) o ci sono casi limite che non conosco?
Non riesco a immaginare alcun vantaggio perché lo _ cattura tutto.

+4

Questi sono davvero uguali, lo trovo anche sciocco. La mia ipotesi è che l'autore volesse essere esplicito. – MasterMastic

risposta

39

non si può semplicemente girare le clausole in giro con la vostra soluzione:

mNull' :: [a] -> Bool 
mNull' _ = False 
mNull' [] = True 

questo sarà sempre resa False, anche se tu passi una lista vuota. Poiché il runtime non considera mai la clausola [], vede immediatamente _ corrispondenze. (GHC vi avvertirà di un modello di tale cumulo.)

D'altra parte,

null' :: [a] -> Bool 
null' (_:_) = False 
null' [] = True 

funziona ancora correttamente, perché non riesce a corrispondere (_:_) caso particolare di una lista vuota.

Questo di per sé non offre realmente un vantaggio alle due clausole esplicite. Tuttavia, nel codice più complicato, la scrittura di tutte le opzioni reciprocamente esclusive ha un vantaggio: se hai dimenticato un'opzione, il compilatore può anche avvisarti di questo! Considerando che un _ può gestire e gestirà qualsiasi caso non trattato dalle clausole precedenti, anche se questo non è effettivamente corretto.

+0

Qualcuno ha idea del perché questo post sia così assurdamente popolare? – leftaroundabout

6

Perché _ significa letteralmente qualcosa oltre a modelli esplicitamente specificati. Quando si specifica (_:_), si intende qualsiasi cosa che possa essere rappresentata come una lista contenente almeno 1 elemento, senza preoccuparsi di cosa o addirittura di quanti elementi contiene effettivamente l'elenco. Poiché il caso con un modello esplicito per la lista vuota è già presente, (_:_) potrebbe anche essere sostituito da _.

Tuttavia, rappresentandolo come (_:_) offre la flessibilità necessaria per non passare esplicitamente il modello di elenco vuoto. In realtà, questo funzionerà:

-- | Test whether a list is empty. 
null     :: [a] -> Bool  
null (_:_)    = False 
null _     = True 

Demo

4

Aggiungo a ciò che è stato detto a sinistra. Questa non è una potenziale preoccupazione per il tipo di elenco, ma in generale i tipi di dati a volte vengono modificati. Se si dispone di un mal concepito

data FavoriteFood = Pizza 
        | SesameSpinachPancake 
        | ChanaMasala 

e poi si impara ad apprezzare DrunkenNoodles e aggiungerlo alla lista, tutte le funzioni che avrà bisogno di essere ampliato pattern match del tipo. Se hai utilizzato qualche pattern _, dovrai trovarli manualmente; il compilatore non può aiutarti. Se hai abbinato ogni cosa in modo esplicito, puoi attivare -fwarn-incomplete-patterns e GHC ti dirà di ogni punto che hai perso.

Problemi correlati