Ok, beru osobní věci zpět. Každopádně můj příspěvek byl z výrazně větší části k tématu, možná bys tedy mohl zareagovat spíš na ty věcné kusy.
Byl. Už jsem si myslel, že to tady nikoho nezajímá ;-)
Dependent typy z principu nemohou dokázat korektnost např. převodu stringu na číslo. Jak by se v typu fce convert: String -> Maybe Nat vyjádřilo, zda se očekává stringový vstup v desítkové nebo šestnáctkové soustavě? Podle mě je to principiálně nemožné, a stejně tak není možné ani vyjádřit korektnost implementace převodu. V Idris se asi dá vyjádřit, že funkce doběhne, a že nezpanikaří, ale to je málo.
Já v těch závislostních typech nejsem kovanej, takže takto si to předstvuju v pseudokódu, jak to chápe typový systém:
parseFromDec :: Str -> Int = ('0' -> 0) | ('1' -> 1) | ... | ('9' -> 9)
případně
parseFromDecM :: Str -> Maybe Int = ('0' -> Just 0) | ('1' -> Just 1) | ... | ('9' -> Just 9) | _ -> Nothing
Plus nějaká recurze.
Píšu, že tak to chápe ten typovej systém, ne, že to tak bude psát programátor. Ten na to musí mět nějaký cukřík - ale tady se zase dostávám do oblasti praktičnosti, a to nepovažuji za námět mé otázky.
Unit testy slouží jako vždy up-to-date dokumentace. U jednoduchých věcí se dá samozřejmě hodně věcí vyčíst z typů (hezký příklad je tady: http://funkcionalne.cz/2014/08/types-will-carry-you-over-the-monads/), ale u složitějších je prostě hezké mít chování zdokumentované na příkladech, místo potřeby rozjímat nad důsledky komplikované typové signatury. Navíc je slušnost mít knihovny zdokumentované, tak proč to rovnou nedělat unit testy? (podívejte např. sem: https://doc.rust-lang.org/std/iter/trait.Iterator.html), všechny Examples jsou rovnou spustitelné unittesty zapsané do docstringů funkcí.
Obecně s tebou naprosto souhlasím. Však já jsem nikde nepsal, že testy jsou zlo.
Ale co by si řekl na to, když by ty ukázkové příklady generoval stroj na požádání? Vzal by sis nějakou funkci, předal jí třeba první argument (a nebo žádný), a stroj by si domyslel tři různé příklady a výsledky, a ty by ti ukázal.
Ono totiž moje zkušenost je taková, že ty ukázky jsou sice fajn, ale stejně mě vždycky zajímala hlavně ta myšlenka, jakási idea té funkce/knihovny/kódu. A na tu většinou autoři zapomínaj - tam ti testy (ale ani typy) nepomůžou.
Unit testy jednoduchým způsobem ověřují chování v krajních a nečekaných případech. Když jsem psal implementaci funkce testující, zda je bod uvnitř polygonu, rovnou napíšu test, jak se chová bod na hraně, jak se chová v polygonu, který není uzavřený, jak se chová v polygonu který protíná sám sebe. Nedovedu si představit, jak by mohlo být takové chování zřejmé z typu funkce. Možná, až BoneFlute přestane "být stále student", nějak pěkně to vyřeší, to by mě pak docela zajímalo.
Byl jsem línej, a napsal jsem si generátor unittestů. Takovej ten postup, kdy si napíšeš prototyp, a pak na něj začneš psát testy - úplně špatně podle TDD, já vím.
Ten generátor měl takové patterny: Int = [INT_MIN, -2, -1, 0, 1, 2, INT_MAX], plus jednoduchá kombinatorika.
Možná, opravdu jen možná, by se z těchto základních patternů dali komponovat/odvozovat složitější třeba pro ten polygon.
Z typu funkce to asi zřejmé nebude. Ale když by ten stroj dokázal vygenerovat ukázky na požádání?
Unit testy jsou šablony funkčního kódu, který používá knihovnu kanonickým způsobem. Kód mohu copy'n'pastnout do vlastního projektu a upravit podle potřeby. Typy tohle neumí.
Viz ten generátor.
A co se týče kanonického způsobu, je otázka jak k tomu přistupovat. Z Haskellu jsem zvyklej, že jinak, než kanonicky to napsat nejde. Prostě ti to nedovolí. (Jen jednou se mi stalo, že jsem kompilátoru zamotal hlavu takovým způsobem, že mi kód napůl blbě přeložil. A bůví, so jsem to ve skutečnosti prováděl.)