109
аргументы не вычисляются до тех пор, пока реально не понадобятся их
значения. В языке Haskell, в основном, используются ленивые вычисления.
Давайте рассмотрим несколько примеров, в которых результат
работы программы зависит от того, принята ли схема ленивых вычислений
с передачей аргументов по необходимости, или схема энергичных
вычислений с передачей аргументов по
значению (понятно, что поскольку
в языке Haskell нет переменных, то и никакой передачи аргументов по
ссылке быть не может). В качестве первого примера заново определим и
подробно рассмотрим определение функции логического "или", которую
мы активно использовали в предыдущем разделе при программировании
регулярных выражений. Уравнение, определяющее работу функции может
выглядеть так:
a `cor` b = if a then True else b
(обозначение операции cor означает «условное или» – «conditional or»).
Попробуем вычислить результат вызова этой функции, передав ей в
качестве аргументов два логических выражения:
(x == 0) `cor` (y / x < 5)
Если в текущем контексте x=2 и y=6, то вычисление происходит
одинаково, независимо от способа передачи аргументов в функцию cor.
Первый аргумент при вычислении в данном контексте выдаст значение
False, а второй аргумент – значение True. Результатом вычтсления всего
выражения будет, соответственно, True. Однако, при x=0 и y=1
вычисление второго аргумента приведет к
ошибке, несмотря на то, что
первый аргумент будет иметь значение True, и ветвь вычислений else, в
которой происходит обращение ко второму аргументу b, вообще не будет
выполняться, так что от значения второго аргумента результат работы
функции не зависит. Но если аргументы будут передаваться в функцию по
значению, то вычисление значений
аргументов будет произведено еще до
начала работы функции, так что в данном контексте программа закончится
аварийно. Если же аргументы будут передаваться по наименованию или по
необходимости, то до обращения ко второму аргументу дело не дойдет,
поскольку функция после вычисления значения первого аргумента сразу
же выдаст значение True. Собственно говоря, это тот
самый эффект, на
который мы и рассчитывали при написании этой функции, и который
использовался нами в предыдущем разделе при определении регулярных
языков. Условное «или» (по МакКарти) именно тем и отличается от
традиционного логического «или», что значение второго аргумента не
будет вычисляться, если при вычислении значения первого аргумента
будет получено значение
True.
В языке Haskell по умолчанию принята схема передачи аргументов
по необходимости, так что используемые нами функции логических «или»
и «и» будут работать так, как задумано. Поскольку никакие выражения в