След като бяхме ангажирани с мързелив език, чистият беше неизбежен. Обратното не е вярно, но е забележимо, че на практика повечето чисти езици за програмиране също са мързеливи. Защо? Тъй като в езика за извикване по стойност, независимо дали е функционален или не, изкушението да се позволят неограничени странични ефекти вътре във „функция“ е почти неустоимо.
Чистотата е голям залог с всепроникващи последици. Неограничените странични ефекти несъмнено са много удобни. При липсата на странични ефекти входът/изходът на Haskell първоначално беше болезнено тромав, което беше източник на значително смущение. Тъй като необходимостта е майка на изобретението, този срам в крайна сметка доведе до изобретяването на монадичен I/O, който сега считаме за един от основните приноси на Haskell към света, както обсъждаме по-подробно в Раздел 7.
Дали един чист език (с монадични ефекти) в крайна сметка е най-добрият начин за писане на програми все още е отворен въпрос, но със сигурност е радикална и елегантна атака срещу предизвикателството на програмирането и именно тази комбинация от сила и красота мотивира дизайнери. В ретроспекция, следователно, може би най-голямата полза от мързела не е мързелът сам по себе си, а по-скоро това, че мързелът ни запази чисти и по този начин мотивира много продуктивна работа върху монадите и капсулираното състояние.
Сега мисля, че важното нещо за мързела е, че той ни поддържа чисти. [...]
[...] ако имате мързелив оценител, е по-трудно да предвидите точно кога един израз ще бъде оценен. Така че това означава, че ако искате да отпечатате нещо на екрана, всеки език за извикване по стойност, където редът на оценка е напълно ясен, прави това, като има нечиста „функция“ — поставям я в кавички, защото сега изобщо не е функция—с тип нещо като низ към единица. Извиквате тази функция и като страничен ефект тя поставя нещо на екрана. Това се случва в Lisp; случва се и в ML. Случва се по същество във всеки език за извикване по стойност.
Сега на чист език, ако имате функция от низ към единица, никога няма да е необходимо да я извиквате, защото знаете, че тя просто дава единицата за отговор. Това е всичко, което една функция може да направи, е да ви даде отговор. И знаете какъв е отговорът. Но разбира се, ако има странични ефекти, много е важно да го извикате. На мързелив език проблемът е, ако кажете „f
приложено към print "hello"
“, тогава дали f
оценява първия си аргумент не е очевидно за извикващия функцията. Това е нещо общо с вътрешностите на функцията. И ако му подадете два аргумента, f
от print "hello"
и print "goodbye"
, тогава можете да отпечатате единия или и двата в който и да е ред или нито един от тях. Така че по някакъв начин, с мързелива оценка, правенето на вход/изход чрез страничен ефект просто не е осъществимо. Не можете да пишете разумни, надеждни, предвидими програми по този начин. Така че трябваше да се примирим с това. Наистина беше малко неудобно, защото всъщност не можехте да правите никакви входни/изходни данни, за които да говорите. Така че дълго време по същество имахме програми, които можеха просто да приемат низ към низ. Това направи цялата програма. Входният низ беше входът, а низът с резултат беше изходът и това е всичко, което програмата наистина можеше да направи.
Може да станете малко по-умни, като накарате изходния низ да кодира някои изходни команди, които са интерпретирани от външен интерпретатор. Така че изходният низ може да каже: „Отпечатайте това на екрана; запишете това на диска. Един преводач всъщност би могъл да направи това. Така че си представяте, че функционалната програма е хубава и чиста и има нещо като този зъл интерпретатор, който интерпретира низ от команди. Но тогава, разбира се, ако прочетете файл, как да върнете входа обратно в програмата? Е, това не е проблем, защото можете да изведете низ от команди, които се интерпретират от злия интерпретатор и използвайки мързелива оценка, той може да изхвърли резултатите обратно във входа на програмата. Така програмата сега приема поток от отговори на поток от заявки. Потокът от молби отива към злия преводач, който прави нещата със света. Всяка заявка генерира отговор, който след това се връща обратно към входа. И тъй като оценката е мързелива, програмата е излъчила отговор точно навреме, за да премине през цикъла и да бъде консумирана като вход. Но беше малко крехко, защото ако консумирате отговора си твърде нетърпеливо, тогава ще получите някакъв вид задънена улица. Защото ще поискате отговор на въпрос, който все още не сте изплюли от задната си част.
Смисълът на това е, че мързелът ни доведе до ъгъла, в който трябваше да измислим начини да заобиколим този I/O проблем. Мисля, че това беше изключително важно. Единственото най-важно нещо за мързела беше, че той ни доведе дотам.
getFirstTrue p = head . filter p
без да се притеснявате, че ще премине през целия списък, преди да върне първия елемент. Ако използвате строга оценка, искате да избегнете това нещо. Това става по-важно с неща като гънки/карти и т.н., смесени заедно. - person Bakuriu   schedule 17.07.2015