Уроки LISP/1: различия между версиями

Материал из LingvoWiki
Перейти к навигацииПерейти к поиску
м (Далі буде, але зараз я йду спати)
 
м (далі буде)
Строка 9: Строка 9:
 
Clojure {{tooltip|реалізовано|реализована}} для JVM, {{tooltip|також|также}} {{tooltip|є|есть}} {{tooltip|реалізації|реализации}} {{tooltip|для деяких|для некоторых}} {{tooltip|інших|других}} {{tooltip|віртуальних|виртуальных}} платформ (CLR (.NET/Mono), JS), {{tooltip|якими|которыми}} {{tooltip|я не користувався|я не пользовался}}, {{tooltip|тому|поэтому}} {{tooltip|нічого|ничего}} {{tooltip|певного|определённого}} {{tooltip|сказати|сказать}} {{tooltip|не можу|не могу}}. {{tooltip|Більшість|Большая часть}} {{tooltip|інформації|информации}} {{tooltip|про Clojure|о Clojure}}, {{tooltip|доступна|доступная}} {{tooltip|в мережі|в сети}}, {{tooltip|стосується|касается}} {{tooltip|JVM-реалізації|JVM-реализации}}.
 
Clojure {{tooltip|реалізовано|реализована}} для JVM, {{tooltip|також|также}} {{tooltip|є|есть}} {{tooltip|реалізації|реализации}} {{tooltip|для деяких|для некоторых}} {{tooltip|інших|других}} {{tooltip|віртуальних|виртуальных}} платформ (CLR (.NET/Mono), JS), {{tooltip|якими|которыми}} {{tooltip|я не користувався|я не пользовался}}, {{tooltip|тому|поэтому}} {{tooltip|нічого|ничего}} {{tooltip|певного|определённого}} {{tooltip|сказати|сказать}} {{tooltip|не можу|не могу}}. {{tooltip|Більшість|Большая часть}} {{tooltip|інформації|информации}} {{tooltip|про Clojure|о Clojure}}, {{tooltip|доступна|доступная}} {{tooltip|в мережі|в сети}}, {{tooltip|стосується|касается}} {{tooltip|JVM-реалізації|JVM-реализации}}.
  
<div style="border-left: solid 3px gray; padding-left: 10px; margin-left: 10px;">'''{{tooltip|Встановлення|Установка}} Clojure (для Windows)
+
{{:Уроки LISP/Додаткова інформація}}
 +
'''{{tooltip|Встановлення|Установка}} Clojure (для Windows)
  
 
{{tooltip|На комп'ютері|На компьтере}} {{tooltip|має бути|должна быть}} {{tooltip|встановлена|установлена}} Java ({{tooltip|якщо|если}} {{tooltip|її нема|её нет}} — {{tooltip|встановіть|установите}}).
 
{{tooltip|На комп'ютері|На компьтере}} {{tooltip|має бути|должна быть}} {{tooltip|встановлена|установлена}} Java ({{tooltip|якщо|если}} {{tooltip|її нема|её нет}} — {{tooltip|встановіть|установите}}).
Строка 26: Строка 27:
 
     java clojure.main %*
 
     java clojure.main %*
 
{{tooltip|Далі|Далее}} {{tooltip|для запуску|для запуска}} {{tooltip|інтерпритатора|интерпретатора}} {{tooltip|будемо|будем}} {{tooltip|використовувати|использовать}} clojure.bat — {{tooltip|для зручності|для удобства}}, {{tooltip|можна|можно}} {{tooltip|створити|создать}} {{tooltip|ярлик|ярлык}} {{tooltip|до нього|к нему}}, {{tooltip|також|также}} {{tooltip|є сенс|есть смысл}} {{tooltip|прописати|прописать}} {{tooltip|шлях|путь}} {{tooltip|до нього|к нему}} {{tooltip|в змінній середовища|в переменной окружения}} path, {{tooltip|щоб|чтобы}} {{tooltip|спростити|упростить}} {{tooltip|запуск|запуск}} {{tooltip|з командного рядка|из командной строки}}.
 
{{tooltip|Далі|Далее}} {{tooltip|для запуску|для запуска}} {{tooltip|інтерпритатора|интерпретатора}} {{tooltip|будемо|будем}} {{tooltip|використовувати|использовать}} clojure.bat — {{tooltip|для зручності|для удобства}}, {{tooltip|можна|можно}} {{tooltip|створити|создать}} {{tooltip|ярлик|ярлык}} {{tooltip|до нього|к нему}}, {{tooltip|також|также}} {{tooltip|є сенс|есть смысл}} {{tooltip|прописати|прописать}} {{tooltip|шлях|путь}} {{tooltip|до нього|к нему}} {{tooltip|в змінній середовища|в переменной окружения}} path, {{tooltip|щоб|чтобы}} {{tooltip|спростити|упростить}} {{tooltip|запуск|запуск}} {{tooltip|з командного рядка|из командной строки}}.
</div>
+
{{:Уроки LISP/Додаткова інформація-кінець}}
  
 
{{tooltip|Робота|Работа}} {{tooltip|з лісп-подібними мовами|с лисп-подобными языками}} {{tooltip|передбачає|предполагает}}, {{tooltip|як правило|как правило}}, {{tooltip|можливість|возможность}} {{tooltip|використання|использования}} {{tooltip|інтерактивного|интерактивной}} {{tooltip|середовища|среды}}, {{tooltip|також|также}} {{відомого|известной}} {{tooltip|як|как}} REPL (Read-Eval-Print Loop — цикл {{tooltip|читання|чтения}}-{{tooltip|обчислення|вычисления}}-{{tooltip|друку|печати}}). {{tooltip|Іншими словами|Другими словами}}, {{tooltip|запустивши|запустив}} {{tooltip|інтерпритатор|интерпретатор}}, {{tooltip|ми можемо|мы можем}} {{tooltip|безпосередньо|непосредственно}} {{tooltip|в ньому|в нём}} ввести {{tooltip|якийсь вираз |какое-то выражение}} {{tooltip|і|и}} {{tooltip|отримати|получить}} {{tooltip|результат|результат}}. {{tooltip|Приклад|Пример}}:
 
{{tooltip|Робота|Работа}} {{tooltip|з лісп-подібними мовами|с лисп-подобными языками}} {{tooltip|передбачає|предполагает}}, {{tooltip|як правило|как правило}}, {{tooltip|можливість|возможность}} {{tooltip|використання|использования}} {{tooltip|інтерактивного|интерактивной}} {{tooltip|середовища|среды}}, {{tooltip|також|также}} {{відомого|известной}} {{tooltip|як|как}} REPL (Read-Eval-Print Loop — цикл {{tooltip|читання|чтения}}-{{tooltip|обчислення|вычисления}}-{{tooltip|друку|печати}}). {{tooltip|Іншими словами|Другими словами}}, {{tooltip|запустивши|запустив}} {{tooltip|інтерпритатор|интерпретатор}}, {{tooltip|ми можемо|мы можем}} {{tooltip|безпосередньо|непосредственно}} {{tooltip|в ньому|в нём}} ввести {{tooltip|якийсь вираз |какое-то выражение}} {{tooltip|і|и}} {{tooltip|отримати|получить}} {{tooltip|результат|результат}}. {{tooltip|Приклад|Пример}}:
  
<div style="border-left: solid 3px blue; padding-left: 5px; margin-left: 5px;">
+
{{:Уроки LISP/Командний рядок}}
 
   Clojure 1.3.0
 
   Clojure 1.3.0
 
   user=> '''''(+ 1 2 3)'''''
 
   user=> '''''(+ 1 2 3)'''''
Строка 41: Строка 42:
 
   (1 2 3)
 
   (1 2 3)
 
   user=>
 
   user=>
</div>
+
{{:Уроки LISP/Командний рядок-кінець}}
 +
({{tooltip|тут|здесь}} {{tooltip|і|и}} {{tooltip|далі|далее}} {{tooltip|дії|действия}} {{tooltip|користувача|пользователя}} {{tooltip|в інтерактивному середовищі|в интерактивной среде}} {{tooltip|виділятимуться|будут выделяться}} {{tooltip|жирним|жирным}} {{tooltip|курсивом|курсивом}}). {{tooltip|Наведені|Приведённые}} {{tooltip|приклади|примеры}} {{tooltip|команд|комманд}} {{tooltip|дуже|очень}} {{tooltip|прості|просты}}, {{tooltip|тому|поэтому}} {{tooltip|однаково|одинаково}} {{tooltip|добре|хорошо}} {{tooltip|підходять|подходят}} для Clojure, Scheme, CL {{tooltip|та інших|и других}} {{tooltip|ліспів|лиспов}}. {{tooltip|Перша дія|Первое действие}} — {{tooltip|додавання|сложение}}. {{tooltip|Особливість|Особенность}} {{tooltip|синтаксису|синтаксиса}} {{tooltip|лісп-подібних|лисп-подобных}} {{tooltip|мов||языков}}: {{tooltip|у всіх|во всех}} {{tooltip|арифметичних|арифметических}} {{tooltip|операціях|операциях}} {{tooltip|використовується|используется}} префіксна нотація, тобто, знак операції йде перед даними (а не посередині, як ми звикли), знак операції й параметри відокремлені один від одного пробілами, а увесь вираз береться в дужки. Така конструція відома під назвою S-вираз (S-expression). Зверніть увагу: дужки тут обов'язкові, їх не можна опускати чи обгортати вираз у додаткові дужки без необхідності — це змінює значення виразу чи призводить до помилки. Дужки вказують на виклик функції чи макроса — порівняйте це з дужками після імені функції в C-подібних мовах. S-вирази є базовим елементом мови, на їх основі будуються не лише арифметичні обчислення чи виклики функцій, а й алгоритмічні конструкції, описи функцій та ін.
 +
 
 +
Ще одна особливість — широке використання функцій зі змінною кількістю параметрів. Прикладами таких функцій є всі арифметичні операції, логічні операції (and, or), функція list (але не cons). Дуже зручно, що операції порівняння також можуть мати довільну кількість параметрів — таким чином, ми можемо записати однією дією порівняння одразу трьох-чотирьох чисел (у звичайній мові програмування нам би довелось писати (A=B)and(B=C), тут же ми пишемо (= A B C), тим самим звільняючись від необхідності двічі писати один і той же параметр, який може бути не лише числом чи змінною, а й вкладеним виразом).
 +
 
 +
'''Декілька слів про list.''' Ця функція просто отримує список параметрів і повертає їх як список. Як бачимо, на виводі цей список подається в дужках, подібно до S-виразів. Цей збіг не випадковий: будь-який вираз у дужках при читанні спершу перетворюється на список, і вже потім при обчисленні перший елемент цього списку інтерпритується як ім'я функції, яку треба викликати. Список необов'язково вводити: його можна згенерувати програмно і, наприклад, інтерпритувати його за допомогою функції eval. Сам же список складається з т.зв. cons-елементів. Такий елемент являє собою запис з двома полями, перше з яких (також відоме як car чи, в термінології Clojure, first) може мати довільний тип, а друге (cdr або rest) є посиланням на інший cons чи ознакою кінця списку. (Власне кажучи, у Scheme чи Common Lisp поле cdr також може мати довільний тип, тоді як у Clojure cons-комірка має дещо складнішу архітектуру і є елементом лінивої послідовності, але про це потім). Як бачимо, три останні вирази є повністю еквівалентними: список можна передати і за допомогою list, і за допомогою cons, якщо другий параметр є списком. Окремий випадок — порожній список (), що одночасно виступає як ознака кінця списку. Його неможливо передати за допомогою cons, хоча (list) без параметрів повертає його.
 +
 
 +
Ми можемо витягнути окремий елемент cons-комірки, використавши функції car та cdr чи first та rest:
 +
{{:Уроки LISP/Командний рядок}}
 +
  user=> '''''(first (list 1 2 3))'''''
 +
  1
 +
  user=> '''''(rest (list 1 2 3))'''''
 +
  (2 3)
 +
 
 +
  SISC (1.16.6)
 +
  #;> '''''(car (list 1 2 3))'''''
 +
  1
 +
  #;> '''''(cdr (list 1 2 3))'''''
 +
  (2 3)
 +
{{:Уроки LISP/Командний рядок-кінець}}
 +
Крім того, існує можливість запису cons-структур з використанням крапки, що відокремлює cdr-частину. Цей спосіб не використовується в Clojure, але належить до базових можливостей синтаксису традиційних ліспів. Все, що записується як (a b c d), можна записати як (a . (b . (c . (d . ())))) — це одне й те ж. Замість (+ 2 2) можна написати (+ . (2 2)) чи (+ 2 . (2)) — результат буде той же. Також можуть існувати cons-структури, другий елемент яких не є cons чи порожнім списком — в цьому випадку, результат буде відображено в з використанням крапки:
 +
{{:Уроки LISP/Командний рядок}}
 +
  #;> '''''(cons 1 2)'''''
 +
  (1 . 2)
 +
{{:Уроки LISP/Командний рядок-кінець}}
 +
Однак, ми не можемо писати (1 . 2) замість (cons 1 2) — це буде помилкою, оскільки першим елементом виразу має бути функція. Помилковим буде й запис (list 1 . 2) — вираз має бути правильним списком. Втім, подібна конструкція використовується, наприклад, при описі функцій зі змінною кількістю параметрів, тому деяка користь з неї є.

Версия 10:13, 1 марта 2012

Загальна інформація

Словом LISP у наш час позначають групу споріднених мов програмування, найпоширенішими Шаблон:Tooltio є Common Lisp, Scheme та Clojure. Існують і інші лісп-подібні мови. І хоча під словом «Лісп» у вузькому розумінні частіше мається на увазі CL, тут ми будемо розглядати переважно Scheme та Clojure.

Для початку, бажано встановити якийсь лісп-транслятор.

Scheme існує в безлічі реалізацій та діалектів, між якими можуть бути деякі відмінності. Я орієнтуюсь переважно на JVM, тому використовую KAWA і SISC, хоча більшість реалізацій Scheme обходяться без джави. З відомих реалізацій можна згадати, наприклад, GNU Guile (не знаю, правда, наскільки воно кросплатфорне в умовах Win32).

Clojure реалізовано для JVM, також є реалізації для деяких інших віртуальних платформ (CLR (.NET/Mono), JS), якими я не користувався, тому нічого певного сказати не можу. Більшість інформації про Clojure, доступна в мережі, стосується JVM-реалізації.

Встановлення Clojure (для Windows)

На комп'ютері має бути встановлена Java (якщо її немавстановіть).

Clojure можна скачати звідси: http://clojure.org/downloads

Скачуємо архів, розпаковуємо (наприклад, у C:\Program Files\clojure-1.3.0\).

В цьому каталозі створюємо файл clojure.bat, відкриваємо його в блокноті, пишемо наступне:

   @echo off
   setlocal
   set CLOJURE_HOME=%~dp0
   if defined classpath (
   set classpath=%CLOJURE_HOME%\clojure-1.3.0.jar;%classpath%
   ) else set classpath=%CLOJURE_HOME%\clojure-1.3.0.jar
   java clojure.main %*

Далі для запуску інтерпритатора будемо використовувати clojure.bat — для зручності, можна створити ярлик до нього, також є сенс прописати шлях до нього в змінній середовища path, щоб спростити запуск з командного рядка.

Робота з лісп-подібними мовами передбачає, як правило, можливість використання інтерактивного середовища, також Шаблон:Відомого як REPL (Read-Eval-Print Loop — цикл читання-обчислення-друку). Іншими словами, запустивши інтерпритатор, ми можемо безпосередньо в ньому ввести якийсь вираз і отримати результат. Приклад:

  Clojure 1.3.0
  user=> (+ 1 2 3)
  6
  user=> (list 1 2 3)
  (1 2 3)
  user=> (cons 1 (list 2 3))
  (1 2 3)
  user=> (cons 1 (cons 2 (cons 3 ())))
  (1 2 3)
  user=>

(тут і далі дії користувача в інтерактивному середовищі виділятимуться жирним курсивом). Наведені приклади команд дуже прості, тому однаково добре підходять для Clojure, Scheme, CL та інших ліспів. Перша діядодавання. Особливість синтаксису лісп-подібних мов: у всіх арифметичних операціях використовується префіксна нотація, тобто, знак операції йде перед даними (а не посередині, як ми звикли), знак операції й параметри відокремлені один від одного пробілами, а увесь вираз береться в дужки. Така конструція відома під назвою S-вираз (S-expression). Зверніть увагу: дужки тут обов'язкові, їх не можна опускати чи обгортати вираз у додаткові дужки без необхідності — це змінює значення виразу чи призводить до помилки. Дужки вказують на виклик функції чи макроса — порівняйте це з дужками після імені функції в C-подібних мовах. S-вирази є базовим елементом мови, на їх основі будуються не лише арифметичні обчислення чи виклики функцій, а й алгоритмічні конструкції, описи функцій та ін.

Ще одна особливість — широке використання функцій зі змінною кількістю параметрів. Прикладами таких функцій є всі арифметичні операції, логічні операції (and, or), функція list (але не cons). Дуже зручно, що операції порівняння також можуть мати довільну кількість параметрів — таким чином, ми можемо записати однією дією порівняння одразу трьох-чотирьох чисел (у звичайній мові програмування нам би довелось писати (A=B)and(B=C), тут же ми пишемо (= A B C), тим самим звільняючись від необхідності двічі писати один і той же параметр, який може бути не лише числом чи змінною, а й вкладеним виразом).

Декілька слів про list. Ця функція просто отримує список параметрів і повертає їх як список. Як бачимо, на виводі цей список подається в дужках, подібно до S-виразів. Цей збіг не випадковий: будь-який вираз у дужках при читанні спершу перетворюється на список, і вже потім при обчисленні перший елемент цього списку інтерпритується як ім'я функції, яку треба викликати. Список необов'язково вводити: його можна згенерувати програмно і, наприклад, інтерпритувати його за допомогою функції eval. Сам же список складається з т.зв. cons-елементів. Такий елемент являє собою запис з двома полями, перше з яких (також відоме як car чи, в термінології Clojure, first) може мати довільний тип, а друге (cdr або rest) є посиланням на інший cons чи ознакою кінця списку. (Власне кажучи, у Scheme чи Common Lisp поле cdr також може мати довільний тип, тоді як у Clojure cons-комірка має дещо складнішу архітектуру і є елементом лінивої послідовності, але про це потім). Як бачимо, три останні вирази є повністю еквівалентними: список можна передати і за допомогою list, і за допомогою cons, якщо другий параметр є списком. Окремий випадок — порожній список (), що одночасно виступає як ознака кінця списку. Його неможливо передати за допомогою cons, хоча (list) без параметрів повертає його.

Ми можемо витягнути окремий елемент cons-комірки, використавши функції car та cdr чи first та rest:

  user=> (first (list 1 2 3))
  1
  user=> (rest (list 1 2 3))
  (2 3)
  
  SISC (1.16.6)
  #;> (car (list 1 2 3))
  1
  #;> (cdr (list 1 2 3))
  (2 3)

Крім того, існує можливість запису cons-структур з використанням крапки, що відокремлює cdr-частину. Цей спосіб не використовується в Clojure, але належить до базових можливостей синтаксису традиційних ліспів. Все, що записується як (a b c d), можна записати як (a . (b . (c . (d . ())))) — це одне й те ж. Замість (+ 2 2) можна написати (+ . (2 2)) чи (+ 2 . (2)) — результат буде той же. Також можуть існувати cons-структури, другий елемент яких не є cons чи порожнім списком — в цьому випадку, результат буде відображено в з використанням крапки:

  #;> (cons 1 2)
  (1 . 2)

Однак, ми не можемо писати (1 . 2) замість (cons 1 2) — це буде помилкою, оскільки першим елементом виразу має бути функція. Помилковим буде й запис (list 1 . 2) — вираз має бути правильним списком. Втім, подібна конструкція використовується, наприклад, при описі функцій зі змінною кількістю параметрів, тому деяка користь з неї є.