(495) 925-0049, ITShop интернет-магазин 229-0436, Учебный Центр 925-0049
  Главная страница Карта сайта Контакты
Поиск
Вход
Регистрация
Рассылки сайта
 
 
 
 
 

Lisp: Слезы радости, часть 3

Источник: rus-linux
Н.Ромоданов

Lisp: Слезы радости, часть 3


Оригинал: "Lisp: Tears of Joy, Part 3 " 
Автор: Vivek Shangari 
Дата публикации: August 1, 2011 
Перевод: Н.Ромоданов 
Дата перевода: Август 2012 г. 

Язык Lisp был оценен, как самый мощный язык программирования в мире. Но только очень небольшой процент самых элитных программистов пользуются им из-за его загадочного синтаксиса и его академической репутации Это весьма печально, поскольку Lisp не так уж и трудно понять. Если вы хотите быть в числе избранных, то эти статьи для вас. Это третья статья в серии, которая началась в июне 2011 года.

Происхождение

К данному моменту большинство из нас согласится, что Lisp является величайшим в мире языком программирования. Для тех из вас, кто еще не согласен, и думаю, что это, вероятно, из-за "огромного раздражающего количества скобок" и я предлагаю читать эту статью с несколькими бутылками пива (для хакеров) или вина (для высоколобой литературной элиты). Прим.пер. - это предложение автора статьи, но не переводчика.

Гай Л. Стил мл. (Guy L Steele Jr) и Ричард П. Габриель (Richard P Gabriel) в своей статье "Эволюция LISP" (PDF), рассказывают, что истоки языка LISP больше лежат в соперничестве, умении перещеголять других, и своему радостному рождению он обязан разным техническим уловкам, характерным для хакерской культуры, а не трезвой оценке технических требований.

Как это все началось? Первые мысли о языке, которым в конечном итоге стал LISP, появились в 1956 году, когда Джон Маккарти (John McCarthy) принял участие в работе летнего Дартмутского проекта по исследованию искусственного интеллекта - Dartmouth Summer Research Project on Artificial Intelligence. Фактическая реализация началась осенью 1958 года. Это выдержки из статьи "Месть полудурков" Пола Грэма ("Revenge of the Nerds", Paul Graham):

"LISP, на самом деле, не создавался как язык программирования, по крайней мере в том смысле, в каком мы понимаем это сегодня, т. е. того, чем мы пользуемся для сообщения компьютеру, что нужно делать. Маккарти (McCarthy), в конечном счете, намеревался разрабатывать язык программирования именно в этом смысле, а LISP, с которым, мы в итоге имеем дело, базировался на другом, что надо было бы рассматривать как теоретическое упражнение - найти более удобную альтернативу машине Тьюринга. Как позже сказал Маккарти: "Еще один способ показать, что LISP был аккуратнее, чем машины Тьюринга, состоял в том, чтобы написать универсальную функцию на LISP и показать, что она короче и понятнее, чем описание универсальной машины Тьюринга. Это была функция LISP eval, которая вычисляет значение LISP-выражения ... При написании eval потребовалось изобрести нотацию, представляющую функции LISP в виде данных LISP, и такая нотация была создана именно для указанных целей, причем не предполагалось, она будет использоваться на практике для записи программ на LISP."

Некоторое время спустя в конце 1958 года, Стив Рассел, один из аспирантов Маккарти, посмотрел на это определение eval и понял, что если он переведет его на машинный язык, то в результате мог бы получиться интерпретатор LISP.

Тогда это было большим сюрпризом. Вот что об этом позже в своем интервью рассказывал Маккарти:

"Стив Рассел произнес: "Послушай, а почему бы мне не запрограммировать эту eval", на что я ему ответил следующее: "Ха, ха, ты путаешь теорию с практикой; эта eval предназначена для чтения, а не для вычислений", но он пошел дальше и запрограммировал. То есть, он перевел eval из моей статьи в машинный код компьютера 704 [IBM], исправил ошибки, а затем разрекламировал его как интерпретатор LISP, которым он, безусловно, стал. Таким образом, в тот момент LISP приобрел, по существу, вид, который он имеет сегодня ... "

Как я понимаю, Маккарти внезапно в течение нескольких недель обнаружил, что его теоретическое упражнение трансформировалось в фактический язык программирования - и более мощный, чем он предполагал (полностью статью читайте здесь).

Теперь, несмотря на то, что мне настолько нравится LISP, что я думаю, что все страницы сайта LINUX For You должны быть посвящены именно ему, я также знаю, что если я хочу продолжать писать для этого сайта, я должен придерживаться, установленного размера статьи. Поэтому хотя нет ничего интереснее, чем происхождение языка LISP, сейчас мы вынуждены перейти к нашей реальной задаче ... (и для тех, кто потерял нить сюжета, это - обучение языку LISP).

Определение локальных переменных в языке LISP

Чтобы определить локальную переменную, используйте команду let. Выражение let состоит из двух частей: первая часть представляет собой список объявлений переменных, где мы можем объявить одну или несколько локальных переменных - они действуют в теле выражения let. Вторая часть является телом выражения let, где мы можем использовать эти переменные. Выражений в теле вычисляются в порядке их следования. Например:

> (let ((x 18)
        (y 13)
        (z 15))
    (+ x y z))
46

Здесь я определил три локальные переменные x, y и z и назначил им значения 18, 13 и 15, соответственно. Каждая пара, состоящая из имени и назначенного имени значения, должна быть заключена в круглые скобки. Также по своему усмотрению используйте отступы, пробелы и разрывы строк - вы можете записать в выражении let переменные и их значения в виде столбца, напоминающего таблицу. Именно поэтому я поместил y непосредственно под x, а zнепосредственно под y. На рис. 1 показаны части выражения let.

Рис.1: Выражение 'let'

Определение локальных функций в языке LISP

Чтобы определить локальную функцию, используйте команду flet. Она также состоит из двух частей: (1) объявления функции и (2) тела команды flet, где функция может быть вызвана. Объявление функции само состоит из имени функции, аргументов этой функции и тела функции, где мы помещаем код функции. Как и для let, мы можем определить одну или несколько функций, которые будут действовать в области видимости flet. Но помните, что эти локальные функции видны только в теле команды - они не могут обращаться друг к другу и, поэтому, рекурсии быть не может. Например:

> (flet ( (foo(n)
                 (+ n 5))
             (bar(n)
                 (+ n 10)))
    (bar (foo 2)))
17

Здесь я объявил две функции: foo и bar. В этом примере, в теле команды flet сначала вызывается функция foo с 2 в качестве аргумента и возвращается значение 7, а затем вызывается функция bar, которая добавляет к этому значению 10, в результате чего в качестве окончательного значения всего выражения flet получается значение 17. Смотрите рис.2.

Рис.2: Выражение 'flet'

Давайте посмотрим, что случится, когда функция bar попытается в собственном теле вызывать функцию foo:

> (flet ( (foo(n)
                 (+ n 5))
            (bar(n)
                (+ (foo 2) n)))
        (bar 10))
 
*** - EVAL: undefined function FOO
The following restarts are available:
USE-VALUE   :R1     Input a value to be used instead of (FDEFINITION 'FOO).
RETRY       :R2     Retry
STORE-VALUE :R3     Input a new value for (FDEFINITION 'FOO).
ABORT       :R4     Abort main loop
>

Именно так! Вы получите ошибку (рис. 3). Команда flet создает локальные функции, которые не видны внутри тела других функций.

Рис.3: Ошибка

Чтобы определить рекурсивные локальные функции воспользуйтесь выражением labels. Локальные функции, определяемые с помощью выражения labels, могут ссылаться на любые другие функции, определенные здесь, в том числе и на себя. Это выражение, по своей базовой структуре, идентично команде flet. Предыдущий код, записанный с использованием labels, будет выглядеть следующим образом:

> (labels ( (foo(n)
                 (+ n 5))
            (bar(n)
                (+ (foo 2) n)))
        (bar 10))
17

В этом примере кода, в теле выражения labels вызывается локальная функция bar. Поскольку в labels локальные функции могут видеть друг-друга, функцияbar вызывает другую локальную функцию (внутри своего собственного тела). Это функция foo, в которой к 5 добавляется 2, в результате чего получается значение 7, к которому, в свою очередь, как к аргументу функции bar, добавляется 10, в результате чего получаем окончательное значение 17.

Здесь я должен проститься с вами на месяц (как быстро кончилось место!), но перед этим я хочу поблагодарить всех тех, кто откликнулся на мою предыдущую статью.

Ссылки по теме


 Распечатать »
 Правила публикации »
  Написать редактору 
 Рекомендовать » Дата публикации: 31.08.2012 
 

Магазин программного обеспечения   WWW.ITSHOP.RU
Zend Studio Commercial License 1 Year Free Upgrades
Business Studio 4.2 Enterprise. Конкурентная лицензия + Business Studio Portal 4.2. Пользовательская именная лицензия. Лицензия на 1 месяц.
Quest Software. TOAD Xpert Edition
Zend Server with Z-Ray Developer Edition - Standard
ABViewer Standart пользовательская
 
Другие предложения...
 
Курсы обучения   WWW.ITSHOP.RU
 
Другие предложения...
 
Магазин сертификационных экзаменов   WWW.ITSHOP.RU
 
Другие предложения...
 
3D Принтеры | 3D Печать   WWW.ITSHOP.RU
 
Другие предложения...
 
Новости по теме
 
Рассылки Subscribe.ru
Информационные технологии: CASE, RAD, ERP, OLAP
Новости ITShop.ru - ПО, книги, документация, курсы обучения
OS Linux для начинающих. Новости + статьи + обзоры + ссылки
Реестр Windows. Секреты работы на компьютере
Один день системного администратора
Каждый день новые драйверы для вашего компьютера!
Новые программы для Windows
 
Статьи по теме
 
Новинки каталога Download
 
Исходники
 
Документация
 
 



    
rambler's top100 Rambler's Top100