Ecco una definizione ragionevole di la wiki di Haskell :
Una funzione totale è una funzione definita per tutti i possibili valori del suo input. Cioè, termina e restituisce un valore.
Una funzione parziale è una funzione che non è definita per tutti i possibili valori di input; in alcuni casi invece di restituire un valore, potrebbe non tornare mai (pensare cicli infiniti), generare un'eccezione (che di solito indica "questo non è definito per questo valore di input" o "input inatteso" o qualsiasi altra cosa) o semplicemente crash del sistema .
Un esempio ben noto di una funzione parziale è la divisione intera, a divided by b
: non è definita quando b
è zero!
Un altro esempio è head
, la funzione Haskell che prende il primo elemento di una lista, che genera un errore se l'elenco è vuoto! Qualcosa del genere:
head :: [a] -> a // this is the signature
head (first : rest) = first
head _ = ... // This is an error! What is the first element of the empty list?
Sfortunatamente alcune funzioni parziali come head
esistono in Haskell per ragioni storiche. Nota che può essere reso totale in questo modo:
headMaybe :: [a] -> Maybe a
headMaybe (first : rest) = Just first
headMaybe _ = Nothing
Quindi puoi tranquillamente chiamare head []
( []
è la lista vuota) e restituirà Nothing
invece di lanciare.
Si noti che quando si guarda il head
originale, non posso sapere solo osservando la sua definizione che potrebbe generare un errore in alcuni casi; Ho bisogno di guardare invece alla sua implementazione! Questo è male. Confronta questo con headOption
: osservando il suo tipo, so che a volte restituisce un Just x
e talvolta un Nothing
, e non devo esaminare l'implementazione.