КОДЕКС
Emacs Lisp
Обзор
На работе использую VSCode, а в личных проектах - Neovim. Долгое время я возился с Emacs, пробуя Spacemacs, Doom Emacs, а также настраивая файлы точек конфигурации с нуля.
Emacs - это больше, чем просто редактор текста / кода (LSP, DAP). Это расширяемая вычислительная среда, которую можно использовать в качестве почтового клиента (mu4e), оконного менеджера (exwm), редактирования удаленных файлов (tramp) и многого другого. С org-mode вы можете использовать Emacs для ведения заметок, списков дел, планирования проектов, создания документов, вычислительных записных книжек, грамотного программирования (Babel) и многого другого.
В отличие от VSCode, с которым легко начать работу и который может быть продуктивным, для Vim и Emacs кривая обучения более крутая, и для того, чтобы быть продуктивным, важно, чтобы вы понимали основы языка, используемого для его настройки.
Emacs Lisp - это диалект языка программирования Lisp, используемый Emacs в качестве языка сценариев. В этой статье давайте изучим основы до уровня, который мы сможем с комфортом использовать для настройки и взлома Emacs.
СОДЕРЖАНИЕ
- "Настраивать"
- "Типы данных"
- Обработка списка
- Определение функций
- Условные
- Основные функции
- Циклы и рекурсия
Настраивать
Оценка Emacs Lisp
При установке Emacs по умолчанию есть несколько способов оценивать выражения Lisp,
- В рабочем буфере введите
C-j
после выражения Lisp, и вывод должен быть сгенерирован немедленно.
(+ 2 2)<---Type C-j 4 <--- Output
- В буфере сразу после выражения Lisp введите
C-x C-e
, чтобы оценить выражение, и результат должен отображаться в эхо-области внизу экрана. Если вы наберетеC-u C-x C-e
, результат будет отображаться в буфере.
Если выражение не вычисляется, введите M-x
и введите lisp-interaction-mode
, lisp-mode
или emacs-lisp-mode
в зависимости от ваших предпочтений.
C-x
означает одновременное нажатие Control
и x
.
M-x
означает одновременное нажатие Alt
и x
.
Если вы предпочитаете интерактивный режим REPL, такой как Python REPL, используйте Inferior Emacs Lisp Mode (M-x
, а затем введите ielm)
.
Полезный
Helpful - это альтернатива встроенной справке Emacs, которая предоставляет гораздо больше контекстной информации.
helpful-callable
helpful-function
helpful-macro
helpful-command
helpful-key
helpful-variable
helpful-at-point
Введите M-x
, package-install
и helpful
, чтобы установить этот пакет.
Helpful предоставляет больше контекстной информации, которая поможет вам в изучении Lisp.
M-x
, helpful-function
, alist-get
, чтобы просмотреть alist-get
документацию по функциям.
Типы данных
Вот несколько основных типов данных Лиспа.
Комментарии начинаются с префикса ;;
;; Number 42 42 3.14139 3.14139 ;; String "Hello World" "Hello World" ;; Character ?a 97 ?\C-c 3 ;; List '(a b c d) (a b c d) ;; Variable buffer-file-name /Users/alpha2phi/README.md ;; Function (point) 663 ;; Array [a b c d e] [a b c d e] ;; Cons cell - Name value pair or tuple (cons 'red 'rose) (red . rose)
Обработка списка
Lisp расшифровывается как LIS t P rocessing с множеством круглых скобок. Некоторые люди даже заявляют, что это название расшифровывается как «Множество изолированных глупых скобок». Списки являются основой Лиспа.
Примеры списков, выделенных жирным шрифтом, и их вывод. После того, как вы наберете выражение Лиспа, нажмите C-j
, чтобы оценить его, и результат должен быть отображен.
'(red blue yellow). <- list (red blue yellow). <- Evaluation output (Press C-j) '("red" "blue" "yellow") ("red" "blue" "yellow") '(1 2 3) (1 2 3)
Это список чисел с оператором * для умножения значений. В выражениях Лиспа используется префиксная нотация.
(* 2 3) 6
Если вы не хотите, чтобы выражение оценивалось, используйте одинарные кавычки. По умолчанию Lisp всегда оценивает выражение.
'(* 2 3) (* 2 3)
И список может содержать другой список.
'(this is a list (with another list)) (this is a list (with another list))
Это пустой список. nil
означает пустой список или ложь.
() nil
t
означает истину, а nil
означает ложь. Все, кроме nil
и пустого списка ()
, считается t
(верно).
(if t 'true 'false) true (if nil 'true 'false) false (if () 'true 'false) false (if "hello" 'true 'false) true
Для правильного отступа кода Lisp введите M-C-\
.
Переменные
Чтобы получить значение предопределенных переменных, просто введите имя переменной, а затем C-j
Чтобы описать встроенную переменную, введите C-h v
, за которым следует имя переменной.
fill-column 70 buffer-file-name nil
Функции
Чтобы запустить функцию, заключите их в круглые скобки. Например. Функция ниже делает номера строк глобально доступными для всех буферов.
Чтобы описать встроенную функцию, введите C-h f
, за которым следует имя функции.
(global-linum-mode t) t
Функции могут принимать аргументы разных типов. Ниже приведены некоторые из встроенных функций.
(concat "hello" " " "world") "hello world" (substring "The quick brown fox jumped." 16 19) "fox" (message "The value of fill-column is %d." fill-column) "The value of fill-column is 70." (number-to-string (+ 2 fill-column)) "72"
Установка значения переменной
Переменные можно установить с помощью set
, setq
или let
.
набор
(set 'colors '(red green blue)) (red green blue) colors (red green blue)
setq
setq
всегда заключает в кавычки первый аргумент и может использоваться для присвоения разных значений разным переменным.
(setq colors '(red green blue)) (red green blue) colors (red green blue) (setq colors '(blue green blue) flowers '(rose violet sunflower)) (rose violet sunflower) colors (blue green blue) flowers (rose violet sunflower)
Его также можно использовать для установки counter
.
(setq counter 0) 0 (setq counter (+ counter 1)) 1 counter 1
пусть
Специальная форма let
предотвращает путаницу. let
создает имя для локальной переменной, которое затмевает любое использование того же имени вне выражения let
.
Локальные переменные, созданные выражением let
, сохраняют свое значение только внутри самого let
выражения (и внутри выражений, вызываемых в выражении let
); локальные переменные не действуют вне выражения let
.
(let ((violet "blue") (rose "red")) (message "Violet is %s and rose is %s." violet rose)) "Violet is blue and rose is red."
let * позволяет использовать ранее связанные переменные в последующих выражениях. Например. значение a
используется для оценки b
.
(let* ((a 1) (b (+ a 2))) (cons a b)) (1 . 3)
Определение функций
Используйте defun
для определения функции.
Пример функции для степени двойки, принимающей 1 аргумент, с именем number
.
(defun power-of-2 (number) "Power of 2" (expt number 2)) power-of-2 (power-of-2 3) 9
Выполните C-h
f
(describe-function
) и введите power-of-2
, чтобы просмотреть документацию по функциям.
Используйте M-q
для форматирования комментария.
Интерактивные функции
Интерактивная функция может быть вызвана с помощью M-x
или клавиш, к которым она привязана. Он также может принимать указанные вами аргументы.
Для следующих двух выражений нажмите C-x C-e
, чтобы оценить их, затем нажмите M-x
, и вы увидите функцию.
N обозначает аргумент числового префикса.
(defun power-of-2 (number) "Interactive Power of 2" (interactive "NEnter number: ") (expt number 2)) power-of-2 (global-set-key (kbd "C-c p") 'power-of-2) power-of-2
Условные
если-то-еще
(setq color 'blue) blue (if (equal color 'blue) ; if-part (message "color is blue") ; then-part (message "color is not blue") ; else-part ) "color is blue"
и, или, не
Помните, что nil
или ()
ложны, t
и все остальное верно. Выражения оцениваются лениво.
(not t) nil (not `a) nil (not nil) t (and t nil) nil (and t ()) nil (or nil t) t
Основные функции - автомобиль, cdr, cons,…
cons
(конструкция) используется для построения списков.car
(содержимое адресной части регистра),cdr
(содержимое декрементирующей части регистра) разделяют списки.
car
возвращает первый элемент в списке.
(car '(red violet blue)) red
cdr
возвращает остальные элементы после первого.
(cdr '(red violet blue)) (violet blue)
cons
для построения списка
(cons 'red '(blue yellow)) (red blue yellow) (cons 'hello 'world) (hello . world)
nthcdr
берет n-е элементы вперед
(nthcdr 1 '(red violet blue green)) (violet blue green)
nth
берет n-й элемент.
(nth 1 '(red violet blue green)) violet
setcar
меняет первый элемент.
(setq colors '(red violet blue green)) (red violet blue green) (setcar colors 'black) black colors (black violet blue green)
setcdr
меняет остальные элементы после первого.
(setq colors '(red violet blue green)) (red violet blue green) (setcdr colors 'black) black colors (red . black)
Обозначение пунктирной пары
Обозначение пунктирной пары - это общий синтаксис для cons-ячеек, который явно представляет CAR и CDR. В этом синтаксисе (a . b)
обозначает cons-ячейку, CAR которой является объектом a
, а CDR - объектом b.
.
Используя cons-ячейки, я могу построить ассоциативный список типа.
(setq alist-of-colors '((rose . red) (violet . blue) (sunflower . yellow))) ((rose . red) (violet . blue) (sunflower . yellow))
И я могу использовать alist-get
, чтобы получить значение по ключу.
(alist-get 'violet alist-of-colors) blue
Используйте setf
, чтобы изменить значение.
(setf (alist-get 'violet alist-of-colors) 'green) green alist-of-colors ((rose . red) (violet . green) (sunflower . yellow))
прогноз
progn
- это специальная форма, которая вызывает последовательное вычисление каждого из своих аргументов, а затем возвращает значение последнего.
(progn (message "line 1") (+ 2 3) ) 5
подать заявление
apply
применяет свой первый аргумент (функцию) к своим остальным аргументам, последний из которых может быть списком.
(apply 'max 3 4 7 3 '(4 8 5)) 8
Циклы и рекурсии
в то время как
Используйте while
, car
и cdr
для прокрутки списка.
(setq colors '(red violet blue green)) (red violet blue green) (while colors (print (car colors)) (setq colors (cdr colors))) red violet blue green nil
Я также могу использовать счетчик для цикла. 1+
и 1-
- встроенные функции для увеличения или уменьшения на 1 от своего аргумента.
(setq counter 10) 10 (let ((total 0) (row-number 1)) (while (<= row-number counter) (setq total (+ total row-number)) (setq row-number (1+ row-number))) total) 55
Долист доживает
Оба dolist
и dotimes
являются макросами Lisp,
Выражение ниже переворачивает список. element
- это элемент в списке, value
- результат.
(setq colors '(red violet blue green)) (red violet blue green) (let (value) ; make sure list starts empty (dolist (element colors value) (setq value (cons element value)))) (green blue violet red)
dotimes
повторяется определенное количество раз, начиная с 0.
(let (value) ; otherwise a value is a void variable (dotimes (number 10) (setq value (cons number value))) value) (9 8 7 6 5 4 3 2 1 0)
Резюме
Изучение Emacs Lisp необходимо для того, чтобы действительно взломать Emacs. Тем, кто предпочитает редактор, который можно взломать, я рекомендую изучить хотя бы основы Emacs Lisp.
Также ознакомьтесь со следующими статьями.
использованная литература
Если вы еще не являетесь участником Medium и хотите им стать, нажмите здесь. (Часть вашей абонентской платы будет использована для поддержки alpha2phi.)