Недавно я решил изучить Лисп, чтобы расширить свой взгляд на разработку программного обеспечения, особенно на функциональное программирование. Я буду описывать свои «открытия» здесь как средство поддержки моего учебного процесса.

Я начал с установки Portacle, полной среды разработки Lisp на основе Emacs, которую вам просто нужно скачать, разархивировать и сразу же приступать к написанию кода. Он имеет Emacs, предварительно настроенный с помощью SLIME, поэтому он всегда соответствует вашим скобкам, обеспечивает завершение кода, документацию и REPL.

Потом я нашел туториал для начинающих под названием Lisp in Small Parts. Он начинается с объяснения полных основ небольшими шагами, чтобы читатель не был перегружен. После каждой части также есть хорошие упражнения, которые дадут вам чувство выполненного долга, когда вы напишете свою первую сверхсложную программу моделирования 6-гранных игральных костей :)

Итак, я скачал и запустил Portacle. Первое, что мне нужно было сделать, это увеличить размер шрифта в Emacs :) Это можно сделать, нажав Ctrl X Ctrl + .

Тогда давайте напишем Лисп. Синтаксис Lisp очень прост. Вы заключаете вызов функции вместе с аргументами в круглые скобки. Внутри круглых скобок вы пишете имя функции (в Лиспе называется процедура) и разделяете пробелами список аргументов. Этот синтаксис действителен для каждого вызова функции, даже для математических операторов, таких как +, -, *, / и т. д.

Итак, чтобы добавить два числа, вы пишете:

(+ 1 2)

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

Но каждый аргумент процедуры может быть вызовом самой процедуры (очевидно). Итак, (2 + 3) * (4 — 5) становится

(* (+ 2 3) (- 4 5))

Обратите внимание, что с синтаксисом со скобками приоритет оператора становится излишним, так как вы всегда сами определяете порядок вычисления. Выражение, конечно, всегда вычисляется, начиная с самых внутренних скобок.

Вы также можете указать более двух аргументов для процедуры.

(+ 1 2 3 4)

Это эквивалентно 1 + 2 + 3 + 4.

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

Это позволяет Lisp обращаться с кодом как с данными, поэтому вы можете писать программы, которые изменяют себя во время работы, и выполнять все другие виды метапрограммирования.

Чтобы создать список в Лиспе, у вас есть процедура list

(list 1 2 3 4)

Он просто выводит (1 2 3 4).

Вы также можете иметь списки внутри списков

(list (list 4 5) (list 1 (list 2 3)))

Выходы

((4 5) (1 (2 3)))

На самом деле в этой части я столкнулся со своей первой проблемой при программировании на Лиспе. Я только что ввел список без ключевого слова list в редакторе следующим образом:

(1 2)

и нажал Enter. Компилятору это, конечно, не понравилось, и он выдал ошибку:

; in: 1 2
;     (1 2)
; 
; caught ERROR:
;   illegal function call
; 
; compilation unit finished
;   caught 1 ERROR condition

И в верхней половине окна Emacs мне были представлены возможные варианты:

Restarts:
 0: [RETRY] Retry SLIME REPL evaluation request.
 1: [*ABORT] Return to SLIME’s top level.
 2: [ABORT] abort thread (#<THREAD “new-repl-thread” RUNNING {1004EB44B3}>)

Так что я просто нажал на 2: [ABORT] и смог продолжить работу.