Začalo to zcela nenápadnou poznámkou pod čarou v
Real world Haskell, že OR
operátor (||
) je v Haskellu definován jako běžná funkce
a zároveň zkratuje (short circuit - první nalezený
true
ukončí vyhodnocování). Proč někdo považuje za důležité
tak běžný fakt explicitně rozebírat mi začalo vrtat hlavou
a na konci vedlo k odhalení jedné fundamentální neznalosti.
Nejdřív k tomu, proč mi to připadalo naprosto samozřejmé:
-
Vždycky jsem si myslel, že operátory jsou de-facto pouze divné funkce. Mohou mít sice infixovou notaci, speciální asociativitu a jiné blbosti, ale v principu je vždy možné sestrojit a použít místo nich běžné funkce. Pro tuhle redundantnost jsem se nikdy moc nezabýval podrobnostmi jejich implementace v jazycích, které to dovolují a proto jsem tak dlouho nezaregistroval svůj omyl.
-
Zkratování logických operátorů je výchozí chování ve všech jazycích, které znám, protože je výhodnější hned z několika důvodů a proto nemá smysl to dělat opačně.
Po chvilce přemýšlení jsem si ale uvědomil, že syntéza těchto dvou předpokladů je překvapivě netriviální. Z principu modelu vyhodnocení “call-by-value” totiž vyplývá, že před voláním funkce dojde k vyhodnocení všech výrazů, které produkují hodnoty vstupující do funkce a proto funkcí není možné simulovat zkratové chování operátoru!
Samozřejmě to lze simulovat funkcemi vyšších řádů, ale to už je takové špinavé inženýrské řešení. Hlavní poučení má být to, že operátory v jazyce mají daleko užší vztah se samotným modelem vyhodnocování daného jazyka (v případě lambda kalkulu konkrétně se specifiky provádění redukčních operací) a proto je informace, která upoutala mojí pozornost na začátku, jednak nesamozřejmá a jednak má zpětně dalekosáhlý význam pro pochopení jazyka jako takového.
Úprava 25. 6. 2018: Na článek reagovat Karel Čížek a.k.a. k47 s ještě hlubším a zajímavějším rozborem.