To je z computer science - všechny typy v haskellu obsahují bottom, no a error je funkce, která díký free theoremům má výstupní typ pouze bottom:
Jinými slovy říkáš, že error má v podstatě nedefinované chování (i když se může vyskytovat v pure kódu!) a neměl by se používat.
Přesně tak. V podstatě jediné rozumné použití je pro to říct "tady je chyba kódu". Nikoliv "toto je chyba vstupních dat". Mimochodem, to, co najdeš v snad i v ubčebnicích je, že když pak budeš mít těch errorů víc, tak je zcela nedeterministické, který z nich to nakonec vyhraje.
Tudíž rozumné použití pro "error" je: kód je špatně. Nikoliv "výjimka na základě vstupních dat, ošetříme, zareagujeme".
Pokud máš pravdu, je docela zarážející, že je to na mnoha místech v Prelude v docela zásadních funkcích:
head :: [a] -> a
head (x:_) = x
head [] = error "Prelude.head: empty list"
Není to tak trochu nebezpečné? Není to tak trochu prasárna?
Ano, je to nebezpečné, ale z úplně jiných důvodů, než které tu diskutujeme. A je to "historický dluh" ("prasárna"), už bylo mnohokrát navrhováno, aby se tyhle funkce z Prelude vyhodily, v podstatě jediný důvod, proč tam zůstávají, je, že to je vcelku přístupné pro začátečníky (učební materiály, jednoduchost..Maybe monad fakt není pro první lekci haskellu vhodný). Spousta lidí taky používá custom Prelude, kde tyhle funkce nemají.
Nicméně důvod, proč to chtějí je úplně jiný, než to, co si asi myslíš. Ono je poměrně korektní, aby "head" zavolal "error", když ho zavoláš na prázdný list. Ty ho totiž nemáš co volat na prázdný list, takže máš chybu v kódu - a bottom je korektní výsledek. Prasárna to začne být v momentě, kdy se tu výjimku pokusíš chytit a na základě ní usuzovat něco jiného než "mám tam internal error".
Ten důvod, proč se to z Prelude snaží dostat je ale jiný: je to "partial" funkce. A Haskellisti nemají partial funkce rádi. Boří to motto "if it compiles, it works". Takže ideálně místo toho všichni používají např.:
NonEmpty a = a :| [a]
head :: NonEmpty a -> a
head (a :| _) = a
nebo
safeHead :: [a] -> Maybe a
safeHead (a:_) = Just a
safeHead [] = Nothing
No a pokud head nepoužiješ a použiješ jednu z těchhle variant, tak ti překladač je schopen garantovat, že to na prázdný list nezavoláš.