Наша программа euler по-прежнему не делает одной вещи, которую выполняет программа на бейсике. Та выдаёт журнал своей работы. Строка PRINT x,y
отчитывается о каждом цикле программы. Такие отчёты нужны для отладки программ, кроме того, они позволяют вести журналы вычислений и других действий.
Для выдачи таких отчётов в LISP-программе придётся также использовать свои механизмы, отличные от применяемых в императивных языках.
Идеальная функциональная программа вообще ничего не меняет в системе, она получает что-то на входе, обрабатывает эти строки, числа и списки по заложенному в неё алгоритму и выдаёт результат. Может быть это даже будет 42 . Она не печатает результатов, не пишет на диск и даже не создаёт переменных, в идеальной функциональной программе даже нет таких понятий. Но в нашем материальном мире такие вещи нужны и LISP умеет обращаться к базам данных, запрашивать ввод от пользователя, писать на диск, использовать переменные и выводить данные на экран. Просто все эти действия называются побочными эффектами, вроде как такой добавкой к основному действию LISP-символа.
Печать на экран — тоже побочный эффект. Для этого есть символ print, который выводит аргумент на экран, а перед ним делает перевод строки. И символы prin1 и princ, разница между ними для нас сейчас непренципиальна. Они просто выводят аргумент на экран, не делая перед ним перевода строки. Печать на экране для них побочное действие, в качестве основного они просто возвращают свой аргумент. Так что (+ 2 3)
просто посчитает выражение (и тоже напечатает его на экране, но это уже любезно сделает для нас интерпретатор лиспа), а (print (+ 2 3))
посчитает выражение и выведет результат на экран.
Зная это совсем просто переделать программу так, чтобы она отчитывалась о ходе вычислений:
(defun euler (y x dx xmax func)
;;;; approximate solution of differential equations of euler method
;;;; print log evry iteration
(if (<= x xmax)
(euler (print (+ (* (funcall func x) dx) y)) (princ (+ x dx)) dx xmax func)
y
)
)
Другие побочные эффекты от этой программы нам не нужны. Мы получили программу:
- гораздо короче, чем исходный код на бейсике;
- более универсальную, она может численно дифференцировать любую, переданную ей функцию одного аргумента;
- более наглядную (хотя тут могут быть совершенно противоположные мнения, всё дело в привычке).
Исходный код приведённого примера можно скачать.