КОДЕКС

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.)