How to start writing Lisp code?
- Tutorial
Often you have to see newbies try Common Lisp and then complain that it’s impossible to work with it normally. As a rule, this is due to the fact that they do not understand how to set up a process for themselves that provides that same “quick response” from the development environment, when you changed the function, compiled it, and the changes immediately began to be used inside the already “running” program without restart it.
To understand how this looks, you can watch some video on youtube, which demonstrates interactive development on Common Lisp.
Today I want to show how to set up a dev environment for such development. In 2018, this became quite simple, thanks to the constantly improving tuling.
I apologize in advance for the fact that the following videos are recorded in Asciinema, and Habrahabr does not support it. Click on the screenshots of the console to watch videos.
First you need to install SBCL , Roswell and Emacs . I'll tell you on the example of installing everything in OSX, and I will be happy if in the comments you share your experience on Windows and Linux. Then I can supplement the article with examples for all three platforms.
SBCL is one of the many implementations of Common Lisp. From open source - the fastest. If desired, the SBCL can run code at a speed comparable to the code in C ++, but at the same time having all the buns from a quick interactive development.
Roswell, is a utility for installing and running Common Lisp programs. Including she knows how to run pre-configured Emacs, as well as build programs into binaries.
You probably know Emacs — an operating system with a code editor. You can write in Common Lisp in any other editor, but today Emacs has better integration and support for code editing. With him you do not have to count brackets, he does everything for you.
So, if you are using OSX, then you need to do
brew install roswell emacs
After the brew will rustle the disk and put everything you need, just run in the terminal:
ros run
This command will automatically install the latest version of SBCL and start the Lisp repl, where you can enter the code:
But this is not the case, to be developed so nelya. So let's set up Emacs for full development:
ros emacs
The command will launch Emacs in the console and configure Quicklisp, a package manager for Common Lisp.
But before we continue, let's set up a terminal, emacs, and OSX so that they work well together.
First you need to change some settings in OSX and iTerm
Make CapsLock work like a Control. In Emacs, without this, nowhere:
Then disable all combinations associated with the use of Control and arrows in MissionControl:
Then put iTerm2 and switch Alt behavior from Normal to Esc + in the profile settings:
After that, create a file with the minimum configuration file for the Emacs, ~/.emacs.d/init.el
:
(package-initialize)
(require 'package)
(add-to-list 'package-archives
'("MELPA" . "http://melpa.milkbox.net/packages/") t)
(defun install-package (package)
(unless (package-installed-p package)
(package-refresh-contents)
(package-install package)))
(install-package 'paredit)
(install-package 'expand-region)
(defun setup-lisp-mode ()
(require 'paredit)
(paredit-mode)
(define-key paredit-mode-map (kbd"C-w") 'paredit-backward-kill-word))
(add-hook 'lisp-mode-hook
'setup-lisp-mode)
(add-hook 'emacs-lisp-mode-hook
'setup-lisp-mode)
;; используем C-w для удаления слова с опечаткой и последующего набора его заново;; вместо kill-region
(global-set-key (kbd"C-w") 'backward-kill-word)
;; вместо кучи команд начинающихся с kmacro-
(global-set-key (kbd"C-x C-k") 'kill-region)
;; вместо indent-new-comment-line
(global-set-key (kbd"M-j")
(lambda ()
(interactive)
(join-line-1)))
;; поиск и замена
(global-set-key (kbd"C-c r s") 'replace-string)
(global-set-key (kbd"C-c r r") 'replace-regexp)
;; по этому сочетанию emacs начинает выделять формы;; и дальше можно просто нажимать =, чтобы расширить;; выделение на родительскую форму.
(global-set-key (kbd"C-c =") 'er/expand-region)
;; это сочетание удобно использовать с предыдущим,;; чтобы быстро выделить и закомментировать кусок кода
(global-set-key (kbd"C-c c") 'comment-or-uncomment-region)
(global-set-key (kbd"C-c C-\\") 'goto-last-change)
(setq custom-file "~/.emacs.d/customizations.el")
(when (file-exists-p custom-file)
(load custom-file))
After that, run ros emacs again, click Alt-X
and enter the command slime
. As a result, we get the command line for entering Lisp commands:
Now you can already code
But we will not enter commands into the repl, it’s better to start the development of microservice right away. If you only need an API, then the easiest way to use Ningle . If you need a more advanced framework such as jung, then you can try Radiance or Caveman2 . But now we will not do anything difficult, but muddle a simple HTTP apish.
Open the file server.lisp
( C-x C-f server.lisp
) in Emacs and start writing code. Like that:
As a result, a web server will be running inside your instance, where you can add routes and redefine views on the fly.
Here is all the code for the lazy:
;; Micro-framework for building API
(ql:quickload:ningle)
;; Now ningle is installed and we need to install a clack which is analog of WSGI;; stack from Python;; I've pressed C-c C-c to eval this form
(ql:quickload:clack)
;; To parse json:
(ql:quickload:jonathan)
(defvar *app* (make-instance 'ningle:<app>))
(setf (ningle:route *app* "/")
;; in case, if you need to parse or serialize JSON,;; use Jonthan library.
(jonathan:to-json '(:foo100500)))
(defvar *server* nil"This variable will store currently running server instance.")
(defun start ()
(if *server*
(formatt"Server already started")
(setf *server*
(clack:clackup *app*))))
(defun stop ()
(if *server*
(clack:stop *server*)
(formatt"Server is not running")))
In Lisp, constructs that are inside parentheses are called “forms.” Forms that are not nested in the top are called top-level. Such forms can be compiled by pressing a combination C-c C-c
when the cursor is inside such a form. If you switch CapsLock
to Сontrol
, then this combination is very convenient to click.
After the form has been compiled, the new version of the function will immediately take effect and no server restart is required. So it is very convenient to debug and fix bugs. In addition, you can configure the automatic test run immediately after compiling a part of the code, but this is a completely different story.
If you are interested in any other topics, write in the comments, I will try to make posts about them.