Skip to main content

Блог инженера

Блог о минимализме, инжинерии и программировании.



Побочные эффекты, как основной результат работы программы

  | #Программирование#LISP

Наша программа 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
        )
)

Другие побочные эффекты от этой программы нам не нужны. Мы получили программу:

  • гораздо короче, чем исходный код на бейсике;
  • более универсальную, она может численно дифференцировать любую, переданную ей функцию одного аргумента;
  • более наглядную (хотя тут могут быть совершенно противоположные мнения, всё дело в привычке).

Исходный код приведённого примера можно скачать.

About Mikhail Kiselev

Photo of Mikhail Kiselev

Приветствую в моём блоге! 😄 Меня зовут Михаил. Я инженер и программист. Живу в Израиле. Но мой блог связан с работой в Сибири и на Сахалине, путешествую где придётся. Я предпочитаю пост в блог посту в твиттер. Описание полезной технологии или гаджета предпочитаю описанию заката или посиделок в кафе.