Připomínky k domácím úkolům
Eukleidův algoritmus
- Řešení, která se snažila kontrolovat vstup (což nebylo nutné), se obvykle nechala vyvést z míry něčím jako pár desítkami devítek na vstupu.
- Na přehození proměnných není potřeba dočasná proměnná: ($x, $y) = ($y, $x % $y)
Context-aware funkce
- Díky za kreativní hlášky :)
- Na vracení false používejte vždy a pouze prázdný return, jinak to v array context udělá neplechu.
- Používejte tříparametrový open. Pokud máte v kódu fce.pl funkci volající open(FILE, $_[0]), co se stane, když tuhle funkci zavolám na >fce.pl?
- Zvykem je spíše nepočítat konce řádků, tj. volat na načtené řádky chomp.
- Přístupů k inicializaci minima se objevilo mnoho: minimum se neinicializovalo a v kódu se kontrolovalo, že je defined; inicializovalo se na inf nebo na „prakctické nekonečno“; nastavilo se podle prvního řádku, byl-li nějaký. Výběr přístup je spíš věcí vkusu.
- Počítání minima/maxima se objevovalo buď iterativní (v každém řádku porovnám), nebo načtením celého souboru do pole a zavoláním min/max, ať už vlastního, či z List::Utils. U druhého přístupu je dobré si uvědomit, že spotřebuje mnohem víc paměti. Jistá optimalizace v tomto případě je neukládat obsahy řádků, nýbrž pouze jejich délky.
- Pěkný způsob dodefinování chování pro prázdné soubory je třeba vracení (0, undef, undef) nebo (0, -1, -1).
Spojový seznam
- Dobrý trik je cyklická reprezentace seznamu – hash reprezentující seznam má klíč pro následující a předchozí prvek, v hodnotách jsou uložené reference na první a poslední prvek seznamu. Při takovéto reprezentaci odpadá obrovská část speciálních případů.
- Zajímavá myšlenka je umožnit vložení (případně smazání) více prvků najednou, implementačně to není o moc těžší než to neumožnit.
- Spíše otázkou k zamyšlení je, co by jednotlivé funkce měly vracet (pokud něco). Co má vracet funkce přidávající prvek? A co funkce, která prvek maže?
- V souvislosti s vracením hodnot pozor na to, že prázdný return vrací false. Nemusí to vadit, ale měli byste to mít na paměti.
- Výpis hodnot je pěkné realizovat přes vrácení hodnot, typicky v poli, a až pak hodnoty opravdu vypisovat.
Pole obsahující odkaz na sebe sama
- Zde mám zejména připomínku k jazyku, až tak mnohoznačná ta čeština není :) Zamýšlená interpretace byla „napište funkci, která vytvoří pole a do tohoto pole vloží referenci na toto pole, které právě vytvořila“. Proti interpretaci „napište funkci, která přijme pole a vloží do něj referenci na toto přijaté pole“ jsem též nic neměla, na jiné interpertace jsem se mračila.
- Pokud vkládáte do cizího pole, dělejte to zásadně přes push/unshift, případně jejich ekvivalenty. Přepsat člověku jeho hodnotu na vaší oblíbené pozici je fuj.
Vlastní Data::Dumper
- Pozor na to, že shift vrací hodnotu odstraněného prvku a některé hodnoty se mohou vyhodnotit jako false. Jinými slovy, while (shift @pole) není dobrý způsob zpracování, protože spadne třeba ve chvíli, kdy pole obsahuje nulu.
- Že se hodnota proménně (nebo třeba prvek pole) vyhodnotí jako false, ještě neznamená, že není definovaná. Připomínám nulu a prázdný řetězec.
- Pokud ošetřujete cykly, hash již spatřených proměnných v žádném případě nesmí být globální. Kromě uživatelsky velmi nepohodlného výpisu tak vůbec nejste schopní vyjádřit, že obsah proměnné se změnil.
- Při detekci cyklu je hezké vidět, nejen že následuje cyklus, ale i která už spatřená proměnná za to může.
- Zejména k zamyšlení se dá nadhodit otázka, jestli je lepší opakující se proměnné pořádně vypisovat hned při prvním potkání, nebo až dodatečně (a při potkáních vypisovat jen identifikátor).
- Pro úplnost, výhoda dodržení syntaxe Dumperu je v tom, že výpis lze pak zpět načíst do proměnné eval-em.
IP adresy
- Je vhodné být konsistentní v (ne)přijímání nul na začátku čísla. Pokud přijímáte 29.01.19.92, ale už ne 29.1.019.92, děláte něco špatně.
- Neopakujte se příliš, škodí to přehlednosti.
- Na tvorbu regexů používejte qr, ušetří vám to spoustu escapování, a modifikátor x. Ten obvykle dost pomůže čitelnosti.
Fold
- Nezapomínejte local-nout proměnné $a a $b. Uživatel má právo mít v nich uložené své hodnoty, a vy nemáte právo mu je přepsat. Zadefinovat si lexikálně lokální $a a $b pomocí my jde, ale obvykle se to nedělá a můžete narazit na problémy s viditelností z volaných kusů kódu.
- Pozor na paměť: argumenty funkce se při rekurzivním volání kopírují, při rekurzivní implementaci vám tedy i pro (relativně) rozumně velká pole hrozí, že paměť prostě a jednoduše dojde.
HTML
- Úkol byl na regex(y), na jeden obrovský, po kouscích poskládaný regex. Parsovat třeba pseudoHTML nějakým postupným zpracováváním řetězce je těžké a obvykle to nefunguje.
Binární stromy obecné i vyhledávací
- Úkol byl tentokrát hodnocen primárně podle funkčnosti a prvního dojmu z kódu.
- Za zamyšlení stojí, jestli vrcholy stromu mají, nebo nemají mít svoji vlastní třídu.
- Pokud si to člověk obhájí před svým svědomím, dá se trocha práce ušetřit tím, že se obecný binární strom buduje od začátku jako cesta (tedy přivěšuje se jen na jednu stranu).
- Výpis prvků se sluší udělat přes vrácení hodnot a jejich následný výpis.
Převod z římských čísel
- Až takové zneužívání whitespace-ů jsme nečekali :) K úlohám takovéhoto typu ale trocha obcházení pravidel patří.