Функциональный язык программирования lisp

LISP. Атом первый

Привет, Хабр!
LISP заинтересовал меня уже давно, но, к сожалению, активно использовать свои знания и стремления на практике шанса не было. Скоро новый учебный год, а значит у меня опять будет возможность изучать и, уже второй год, преподавать студентам LISP. Еще одной проблемой, кроме традиционного отсутствия интереса к сложным вещам, кажется отсутствие литературы. Да и вообще, тема LISP-а в интернете, а тем более в рунете освещена слабо. Вот и на Хабре публикаций довольно мало.

Надеюсь, эта статья понравится общественности и откроет серию, повествующую об одном из наиболее интересных и наименее понятных (хотя до brainfuck и далеко) языков программирования – LISP. Ведь, как это не банально, еще один язык — еще одна жизнь

Начнем с базовых понятий LISP-а – атомов и списков. Немного позже, если будет интересно, в приквеле «Атоме нулевом» можно будет более подробно поговорить о философии и причинах возникновения LISP, а так же о современных направлениях его использования.

Краткая история

LISP был придуман Джоном Маккарти в 1958 году для решения задач нечислового характера и базировался на трех основных китах: алгебре списочных структур, лямбда исчислении, теории рекурсивных функций. Долгое время LISP использовался исключительно узким кругом специалистов по искусственному интеллекту. Но, начиная с 80-х годов прошлого века, LISP начал набирать обороты и сейчас активно используется, например, в AutoCad и Emacs.

Типы данных

Традиционно в LISP рассматривают два типа атомов: символы и числа. Символы могут обозначать числа, строки, сложные структуры, функции и другие объекты. Ограничения на имена символов зависят от используемого диалекта, но большинство из них не накладывает практически никаких ограничений на используемые в именах символы. Кроме того, опять же в большинстве диалектов, имена символов не зависят от регистра.
Некоторые символы имеют специальное назначение – это константы, встроенные функции, T (true, истина) и NIL (false, ложь).

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

Например, точечными парами являются выражения:

Атомы и точечные пары объединяют под общим названием S-выражения (S-expression, symbolic expression). Особым видом S-выражения является список, выражаемый следующим образом:

NIL в большинстве случаев определяется как пустой список, в таком случае определение списка можно переписать следующим образом:

Крылья, ноги… Главное хвост

И голова и хвост являются ключевыми понятиями в списочном контексте LISP. Первый элемент списка именуется головой списка, все остальные элементы – хвостом. Для работы с головой и хвостом существует набор базовых функций, рассмотренный немного ниже.
Пустой список эквивалентен паре пустых скобок:
NIL ().
Непустой список, состоящий из элементов a1, a2, a3… в соответствии с правилами записи S-выражений может быть записан следующим образом:

В LISP список можно записать и последовательностью элементов, заключенных в скобки и разделенных пробелами. По большему счету, список – это многоуровневая структура данных, для которой архиважна последовательность открывающих и закрывающих скобок.
Элементами списка могут быть атомы и списки, в том числе и пустой список. Например, () – пустой список, а (NIL) – список, состоящий из одного элемента NIL – что эквивалентно (()).
Следует понимать, что обычный синтаксис S-выражений может использоваться наравне со списочным синтаксисом, например, следующие выражение эквивалентны:

(a.(b.nil)), (a b.nil), (a b nil), (a b)

Если кому-нибудь интересно – можно будет рассказать и о внутреннем представлении списков в памяти. Это вполне самостоятельная и по интересу и по объему тема.

Основные функции и предикаты

В LISP существует довольно небольшой набор примитивных функций, обеспечивающий полноценную возможность обработки списков. В контексте списочных структур данные функции являются аналогом основных арифметических действий и образуют некую систему правил, к которой сводятся абсолютно все символьные вычисления.

Традиционном к базовым функциям относят QUOTE, CAR, CDR, CONS, ATOM, EQ.

Функция QUOTE

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

Функцию QUOTE можно записать и короче:

Функция CAR

Предназначена для получения первого элемента точечной пары (или же головы списка). Использование данной функции возможно лишь в списочном контексте, использование для атома приведет к ошибке.

Для удобство головой пустого списка считается NIL.

Фунция CDR

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

Хвостом списка является весь список без первого элемента. Если список состоит из одного элемента, хвостом будет NIL. Хвостом пустого списка для удобства так же считается nil.
Несколько примеров:

Функции CAR и CDR реализованы во всех диалектах LISP, но в некоторых для них созданы и синонимы: FIRST и REST, HEAD и TAIL).

Функция CONS

Фактически функция CONS является антиподом функций CAR и CDR:

Функция ATOM

ATOM и EQ являются предикатами – т.е. функциями, проверяющих соответствие аргумента некоторому свойству и возвращающими T или NIL в зависимости от успешности проверки.

Предикат ATOM проверяет, является ли объект, переданный в качестве аргумента, атомом:

atom (S-выражение)

Функция EQ

Предикат, проверяющий идентичность двух символов.

eq (атом, атом)

Следует помнить, что предикат EQ применим лишь к атомарным аргументам и не может быть использован для списков. Так же не следует использовать EQ при сравнении чисел.

Более общим по сравнению с EQ является предикат EQL, позволяющий сравнивать однотипный числа:

Еще более общим для чисел является предикат =, позволяющий сравнивать значения чисел различных типов:

Более общим для списков является предикат EQUAL, позволяющий сравнивать идентичность двух списков:

Наиболее общим предикатом является EQUALP, позволяющий сравнивать произвольные объекты.

Функция NULL

NULL проверяет, является ли объект, переданный в качестве аргумента, пустым списком:

Судя по двум последним примером, можно сделать вывод, что функцию NULL можно использовать и как логическое отрицание. Для этих же целей в LISP существует и предикат NOT.

Что дальше?

Надеюсь, что смог заинтересовать. В следующий раз я планирую рассказать о существующих диалектах LISP (хотя на первых порах достаточно будет университетского XLisp), менее часто используемых базовых функциях, сворачивании CAR и CDR в что-то вроде CAAAADDAAR и определении собственных функций. Позже — рекурсия, управляющие структуры, область действия, ввод-вывод. Еще позже — если не надоем — о функционалах, макросах, свойствах символов и замыканиях. Ну и конечно, о том, о чем попросит общественность.
До встречи!

Источник

Функциональные языки программирования: LISP (Scheme/Racket) + Haskell. Использование рекурсии для решения задач

Функциональное программирование — раздел дискретной математики и парадигма программирования, в которой процесс вычисления трактуется как вычисление значений функций в математическом понимании (в отличие от функций как подпрограмм в процедурном программировании). У функции в математике есть аргументы и результат, она не меняет состояние остальной программы (отсутствуют побочные эффекты).

Противопоставляется парадигме императивного программирования, которая описывает процесс вычислений как последовательное изменение состояний (как в теории автоматов).

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

Сильная (строгая) и слабая типизация

Существуют различия в понимании функции в математике и функции в программировании, вследствие чего нельзя отнести Си-подобные языки к функциональным, использующим менее строгое понятие. Функция в математике не может изменить вызывающее её окружение и запомнить результаты своей работы, а только предоставляет результат вычисления функции.

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

Дополнительное отличие от императивных языков программирования заключается в декларативности описаний функций. Тексты программ на функциональных языках программирования описывают «как решить задачу», но не предписывают последовательность действий для решения.

Вариант данного языка широко используется в системе автоматизированного проектирования AutoCAD и называется AutoLISP

Основные преимущества функциональных языков:

Краткость и простота

Программы на функциональных языках обычно намного короче и проще, чем те же самые программы на императивных языках.
Пример (быстрая сортировка Хоара на абстрактном функциональном языке):

Строгая типизация

В функциональных языках большая часть ошибок может быть исправлена на стадии компиляции, поэтому стадия отладки и общее время разработки программ сокращаются. Вдобавок к этому строгая типизация позволяет компилятору генерировать более эффективный код и тем самым ускорять выполнение программ.

Модульность

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

Функции — объекты вычисления

В функциональных языках (равно как и вообще в языках программирования и математике) функции могут быть переданы другим функциям в качестве аргумента или возвращены в качестве результата. Функции, принимающие функциональные аргументы, называются функциями высших порядков или функционалами.

Чистота (нет побочных эффектов)

В чистом функциональном программировании оператор присваивания отсутствует, объекты нельзя изменять и уничтожать, можно только создавать новые путем декомпозиции и синтеза существующих. О ненужных объектах позаботится встроенный в язык сборщик мусора. Благодаря этому в чистых функциональных языках все функции свободны от побочных эффектов.

Отложенные (ленивые) вычисления

В императивных языках программирования (например, C++) вызов функции приводит к вычислению всех аргументов. Этот метод вызова функции называется вызов-по-значению. Если какой-либо аргумент не использовался в функции, то результат вычислений пропадает, следовательно, вычисления были произведены впустую. Противоположностью вызова-по-значению является вызов-по-необходимости (ленивые вычисления). В этом случае аргумент вычисляется, только если он нужен для вычисления результата.

Скачивание и установка

Программы и данные неотличимы друг от друга — всё есть списки.

Программа на языке LISP — список. Первый элемент списка — имя функции которую надо вызвать, остальные — аргументы.

Сначала вычисляются аргументы.

Функция list конструирует список:

Условный оператор (больше похож на тернарный)

Конструирование списка из головы и конца:

Разберем и построим снова список L :

null? — пуст ли список?

Вычисление длины списка

Получить элемент списка L с номером n

Факториал Применить одну операцию ко всем элементам списка

(close-output-port out) — закрытие файла (нужно при работе в среде разработки)

Тексты программ на функциональных языках программирования описывают «как решить задачу», но не предписывают последовательность действий для решения.

Первым спроектированным функциональным языком стал Лисп.

Лисп является вторым в истории (после Фортрана) используемым по сей день высокоуровневым языком программирования.

Haskell

Концепция языка отражает идею математика Хаскелла Карри, писавшего, что «доказательство — это программа, а доказываемая формула — это тип программы». Именно в честь Х. Карри язык и получил своё название.

Источник

Функциональный язык программирования lisp

Лисп (LISP, от англ. LISt Processing language — «язык обработки списков»; современное написание: Lisp) — семейство языков программирования, программы и данные в которых представляются системами линейных списков символов. Лисп является вторым в истории (после Фортрана) используемым по сей день высокоуровневым языком программирования. Создатель Лиспа Джон Маккарти занимался исследованиями в области искусственного интеллекта (в дальнейшем ИИ) и созданный им язык по сию пору является одним из основных средств моделирования различных аспектов ИИ.

Традиционный Лисп имеет динамическую систему типов. Язык является функциональным, но многие поздние версии обладают также чертами императивности, к тому же, имея полноценные средства символьной обработки становится возможным реализовать объектно-ориентированность, примером такой реализации является платформа CLOS.

Язык Лисп, наряду с языком Ada, прошел процесс фундаментальной стандартизации для использования в военном деле и промышленности, в результате чего появился стандарт Common Lisp. Его реализации существуют для большинства платформ.

Одной из базовых идей языка Lisp является представление каждого символа как узла многокоординатной символьной сети; при этом координаты, свойства, уровни сети записаны в так называемых слотах символа. Основные слоты:

Язык Лисп является языком системного программирования для так называемых Лисп-машин, производившихся в 80-е годы, например, фирмой Symbolics.

Содержание

Синтаксис

Основной механизм языка Лисп — инкапсулированная в список определяющая голова списка и подключённый к ней хвост списка, который рекурсивно также может быть списком. Лисп-машина способна воспринимать каждый поступающий на неё список на самом абстрактном уровне, например как мета-Лисп-машину, модифицирующую воспринимающую машину. В такой динамичной, высокоабстрактной среде можно реализовать как строго научные системы, так и неисчислимое множество программистских трюков и генераторов всевозможных машин.

Любая программа на языке Лисп состоит из последовательности выражений (форм). Результат работы программы состоит в вычислении этих выражений. Все выражения записываются в виде списков — одной из основных структур Лиспа, поэтому они могут легко быть созданы посредством самого языка. Это позволяет создавать программы, изменяющие другие программы или макросы, позволяющие существенно расширить возможности языка.

Внешне исходный код программы на Лиспе отличается обилием круглых скобок; редактирование программ значительно упрощается использованием текстового редактора, поддерживающего автоматическое выравнивание кода, подсветку соответствующих пар скобок и такие специальные команды, как «закрыть все открытые скобки», «перейти через список вправо» и т. д. [1]

s_expression ::= atomic_symbol | «(» s_expression «.» s_expression «)» | list

atomic_symbol ::= letter atom_part

atom_part ::= empty | letter atom_part | number atom_part

Примеры

Пример программы, выводящей сообщение «Hello, world!»:

Источник

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

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

В то время я считал, что я был асом в крутом современном объектно-ориентированном языке программирования, который был средством моего самовыражения: я ел, пил, спал и мечтал на этом языке. Он сделал меня Богом в моем компьютерном мирке. Я также верил, что я нравлюсь женщинам, проводил часы, приводя в порядок свою прическу, и вел свой старенький и потрепанный скутер Kinetic Honda точно так, как если бы это был крутейший спорт-байк 1340cc Suzuki Hayabusa.

Дежа вю

Три недели на изучение Lisp-а и у меня возникло ощущение дежа вю — так было раньше, когда я сначала «продвигался» от BASIC к С и от С к C++ и к Java. Тогда на каждом шаге я приятно удивлялся растущей мощью (программирования), оказавшейся в моих руках. Снова и снова я удивляюсь, как я кодировал без объектов, методов, инкапсуляции, полиморфизма, наследования и так далее! Можно сказать, что это синтаксические сладости моей работы.

В своем знаменитом эссе «Как стать хакером» («How to become a Hacker») Эрик Стив Реймонд (Eric Steven Raymond), автор многих бестселлеров, в том числе бестселлера «Собор и базар» («The Cathedral and the Bazaar»), пишет: «Обучение в Lisp-е состоит в получении практического опыта, которым вы будете обладать, когда вы его, наконец, освоите. Этот опыт, даже если вы больше никогда не будете пользоваться языком Lisp, сделает вас лучшим программистом на всю оставшуюся жизнь».

Lisp научит вас как специалиста

Так что же такого замечательного в Lisp? Как это он вас научит как специалиста? Специалист по Lisp-у Пол Грэм (Paul Graham) объясняет это так искусно и методически, что неуместно отвечать на этот вопрос по-иному. Пять языков (Python, Java, C/C++, Perl и Lisp), которые Эрик Рэймонд (Eric Raymond ) рекомендует осваивать специалистам, сильны каждый по-своему. В каких-то специальных вопросах, каждый из них может уступать другому, но, я думаю, что выше всех находится Lisp. И в пользу этого утверждения, я расскажу вам об одной из возможностей, которая, как я считаю, когда я смотрю на другие четыре языка, просто забыта. Что вы в них можете сделать без макросов?

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

Если вы разбираетесь в том, как работают компиляторы, вы поймете, что дело на самом деле не в том, что в Lisp используется странный синтаксис (везде круглые скобки!), а в том, что в нем нет синтаксиса (на самом деле синтаксис присутствуют в любом языке; в языке Lisp используется чрезвычайно простой и интуитивно понятный синтаксис с использованием круглых скобок — прим.пер.). Вы пишете программы в виде деревьев синтаксического разбора, которые создаются компиляторами, когда те выполняют синтаксический анализ других языков программирования. И эти деревья разбора полностью доступны для ваших программ. Вы можете писать программы, которые обрабатывают эти деревья. В Lisp, эти программы называются макросами. Это те программы, которые пишут программы. (Если вы никогда не хотите попасть в «Матрицу», вы должны быть довольны тем, что вы управляете Lisp-ом).

Мы знаем, что язык Java должен быть достаточно хорошим, поскольку это крутой язык программирования. Так ли это? В субкультуре хакеров, есть еще один язык, называемый Perl, который считается еще более крутым, чем Java. Но есть еще один язык, Python, пользователи которого обычно смотрят свысока на Perl, и есть еще один язык, называемый Ruby, который некоторые считают наследником языка Python.

С 1958 года языки программирования почти догнали Lisp! Первоначально Lisp был создан Джоном Маккарти (John McCarthy) в 1958 году и только сейчас популярные языки программирования догнали те идеи, которые в нем были тогда разработаны.

Lisp просветит вас как личность

Все женатые мужчины будут солидарными со Стивеном Леви (Steven Levy), когда он в своей книге «Хакеры: Герои компьютерной революции» (Hackers: Heroes of the Computer Revolution) приводит пример того, как мыслят хакеры. Мардж Сондерс должна была утром в выходной день вернуться в гараж и попросила своего мужа Боба о следующем: «Есть ли у тебя желание помочь мне отнести продукты?». На что тот ответил: «Нет».

Когда я обычно программировал на моем любимом языке программирования, поддерживающим объектное ориентирование, мой ответ бы не отличался. К счастью для меня, я открыл Lisp. Это дало мне целостное представление о себе, космосе, а также научило меня, что есть лучшие ответы на вопрос, чем просто «да» или «нет».

С тех пор я узнал, что правильный ответ на вопрос Мардж Сондерс был бы: «Конечно, дорогая! Тебе нужно, чтобы я еще что-нибудь сделал для тебя?». Излишне говорить, что моя жена счастлива и в прошлом месяце мы отпраздновали наш седьмой год совместной семейной жизни.

Граница функционального программирования

В своей знаменитой работе «Why Functional Programming Matters» (Прим.пер.: Есть перевод этой статьи на русский язык — смотрите его по ссылке «Сильные стороны функционального программирования» ) эксперт по компьютерным наукам Джон Хьюз (R John M Hughes) говорит, что традиционные языки программирования смещают концептуальные ограничения в ту сторону, где проблемы могут быть решены с помощью разбиения на модули. Функциональные языки программирования снимают эти ограничения.

Начинаем

Любой язык, который подчиняется принципам языка Lisp, считается диалектом Lisp. Тем не менее, подавляющее большинство сообщества Lisp использует следующие две версии: ANSI Common Lisp (часто сокращаемый до CL) и Scheme. Здесь, я буду говорить исключительно о диалекте ANSI Common Lisp, чуть более популярном из двух этих диалектов.

Есть много отличных компиляторов Lisp. Но проще всего для начала воспользоваться пакетом CLISP — компилятором Common Lisp с открытым исходным кодом. Он прост в установке и работает в любой операционной системе — на платформах Windows, Mac и в различных вариантах Linux. Пользователи Mac, возможно, захотят воспользоваться компилятором LispWorks, который будет проще заставить работать на их машинах.

Устанавливаем CLISP

Запускаем его

Функциональный язык программирования lisp. Смотреть фото Функциональный язык программирования lisp. Смотреть картинку Функциональный язык программирования lisp. Картинка про Функциональный язык программирования lisp. Фото Функциональный язык программирования lisp

В выражении (* 7 (+ 4 3)) символы * и + называется операторами, а числа 7, 4 и 3 называются аргументами.

В повседневной жизни мы должны были бы писать это выражение как ((4 + 3) * 7), но в Lisp мы первым помещаем оператор, за которым идут аргументы, а все выражение заключаем в круглые скобки. Это называется префиксной нотацией, поскольку на первом месте стоит оператор.

Кстати, если вы допустили ошибку и CLISP начнет вести себя ненормально, просто наберите команду :q и все будет исправлено. Если вы хотите завершить работу CLISP, просто наберите команду ( quit ).

А что под «капотом»?

Давайте не будем идти традиционным путем, начиная изучать с азов (изучение синтаксиса языка, его основных функций и т.д.). Иногда, выяснение деталей, лежащих в основе, оказывается более трудным, чем общее понимание возможностей. Конрад Барский (Conrad Barski) пытаясь заинтересовать нас языком Lisp, показывает, как на нем написать игру. Давайте воспользуемся его методом и напишем простую игру с интерфейсом из командной строки, в которой используется алгоритм двоичного поиска.

Вот как Барский объясняет игру:

Чтобы создать эту игру, нам нужно написать три функции: guess-my-number (отгадывание-числа), smaller (число-меньше) и bigger (число-больше). Игрок просто вызывает эти функции в цикле REPL. Чтобы вызвать функцию в Lisp, вы должны заключить ее в скобки, а также указать любые параметры, которые вы хотите передать в функцию. Поскольку для этих функций не требуется никаких параметров, мы, когда входим в них, просто заключает названия этих функций в скобки.

Стратегия этой игры следующая:

В Common Lisp функции определяются с помощью определения defun следующим образом:

Что делает эта функция? Как уже говорилось ранее, число, которое должен отгадать компьютер, будет лежать между двумя предельными значениями. Поэтому мы выбираем среднее значение, лежащее между двумя пределами. Но если среднее значение заканчивается дробной частью, мы будем использовать ближайшее к нему целое значение, поскольку мы отгадываем только целые числа.

Мы реализуем это в функции guess-my-number, добавив сначала цифры, которые представляют собой верхний и нижний пределы, затем с помощью функции арифметического сдвига ash делим пополам сумму пределов и сокращаем возможные результаты. Встроенная функция ash в Lisp берет число в двоичном виде и сдвигает его двоичные разряды влево или вправо, отбрасывая те биты, которые теряются в процессе сдвига. Например, число 11, записанное в двоичном формате, имеет вид 1011. Мы можем сдвинуть биты с помощью комады ash влево на 1 позицию, которая указывается в качестве второго аргумента:

Давайте посмотрим, что происходит, когда мы вызываем нашу новую функцию:

Поскольку это наша первая догадка, то значение, которое мы видим, когда вызываем эту функцию, указывает, что все происходит так, как и планировалось: программа выбрала номер 50, который как раз посередине между 1 и 100. Теперь, давайте напишем наши функции smaller и bigger. Точно также как и функция guess-my-number, они являюся глобальными функциями, определяемыми с помощью defun :

Во-первых, давайте воспользуемся defun для того, чтобы начать определение новой глобальной функции smaller. Затем воспользуемся функцией setf для изменения значения глобальной переменной *big*. Поскольку мы знаем, что число должно быть меньше, чем последняя догадка, наибольший предел должен быть на единицу меньше, чем последнее значение, предложенное в качестве догадки.

Это вычисляется с помощью кода (1- (guess-my-number)) следующим образом: сначала вызывается наша функция guess-my-number, которая берет самое последнее значение, предложенное в качестве догадки, и с помощью функции 1- из результата вычитается 1.

Наконец, мы хотим, чтобы наша функция smaller показала нам новую догадку. Мы делаем это, поместив вызов функции guess-my-number в последней строке в теле функции. На этот раз функция guess-my-number будет использовать обновленное значение *big*, в результате она вычислит следующую догадку. Окончательное значение нашей функции будет возвращено автоматически, в результате чего наша новая отгадка (сгенерированная функцией guess-my-number) должна быть возвращена функцией smaller.

Чтобы завершить нашу игру, давайте добавим функцию start-over, которая будет перезагружать наши глобальные переменные:

На рис.2 наша игра показана в действии для случая, когда загадано число 74.

Функциональный язык программирования lisp. Смотреть фото Функциональный язык программирования lisp. Смотреть картинку Функциональный язык программирования lisp. Картинка про Функциональный язык программирования lisp. Фото Функциональный язык программирования lisp

Рис.2: Игра в действии.

В следующих статьях мы вернемся к изучению с азов и начнем с базового синтаксиса и семантики языка.

Источник

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *