粗魯先生Lisp再出發
開始的原因
目標和夢想是最近考慮的一個問題。什么是目標?什么是夢想?夢想可以激勵改變,目標才能實現改變。
開始這個部分的時候,我的夢想是什么?我的目標是什么?我想要什么?我要做什么?
- 逃避手頭的項目
- 逃避手頭的工作
學習Lisp可以回溯到大學時期,為什么要學這么奇怪的東西呢?也看過《畫家和黑客》這本書,時斷時續地看過一些比較外圍的Lisp博客,甚至書籍。但是Lisp從來沒有成為生產力工具,也沒有形成任何成果。
那么,到底行不行呢?
所以,這次被手頭的工作壓垮的時候,我又退回到曾經的路徑,逃避到學習一個新的、或者舊的編程語言上。好多編程語言就是這樣學會的……這個策略就跟失眠就去學微積分一樣,要么學了一點人類最高級的智慧,要么困了就睡著了。
那么這一次Lisp的學習,又會怎么樣呢?能不能讓我在被死線壓垮的時候,擺一個更加優雅的姿勢呢?希望能夠吧……Lisp如此優雅,這次我一定會死得很優雅吧。
實用的目標
跟以前學習Lisp不同的是,這次我想選擇一個更加實用的目標。第一時間想到的是,我要不要把我經常寫給別人的小工具,用Lisp來實現呢?通常,我用Python來寫這些,但是給別人的時候總是有這樣那樣的問題。
比如說,真的很多人根本不可能裝Python,所以我會感染每一個我接觸的電腦,我用過之后,這些電腦上總是被被裝上Python。
我會用pyinstaller打包,但是Pyinstaller打包的過程和結果,總是讓人有一點點不放心。每次成功了我總是會覺得自己很幸運。
那么,Lisp是不是一個很好的選擇呢?
根據我那些遠古時代關于Lisp的記憶,加上一點點搜索,結論是:相當行。只要你能跟Lisp在一定的程度上不相互抵觸……
這次重新開始Lisp,我準備戴上一頂粗魯先生的帽子,簡單粗暴地對待Lisp,毫不理會Lisp那些優雅、美好的特性,只要能用就行。
開始的過程
稍微看一下,現在開發Lisp大概有兩個主要的流派(單純是個人觀點):
- Emacs Lisp
- Common Lisp
開發環境同樣有兩個主要的流派:
- Emacs
- VSCode
這兩個并不是完全對應的,因為Emacs啥都行,VSCode搞Emacs Lisp估計比較抽象。
我選擇的是Common Lisp和VSCode。至于Common Lisp的實現,直接說結論:SBCL。
- 安裝SBCL
- 安裝VSCode
- 安裝alive插件
- 安裝quicklisp
- 安裝alive-lsp
- 安裝alive插件
- 開始寫代碼
- 產生一個可執行文件
SBCL安裝
SBCL是Steel Bank Common Lisp的縮寫,是一個Common Lisp的實現。在這里可以找到各種平臺的安裝方法。
或者,如果不是windows,可以直接用包管理器安裝:
sudo apt-get install sbcl
安裝好之后,可以考慮把SBCL的路徑加到環境變量里面。之后就能在任意地方打開終端,輸入sbcl
,就能進入SBCL的REPL了。
This is SBCL 2.4.6, an implementation of ANSI Common Lisp.
More information about SBCL is available at <http://www.sbcl.org/>.SBCL is free software, provided as is, with absolutely no warranty.
It is mostly in the public domain; some portions are provided under
BSD-style licenses. See the CREDITS and COPYING files in the
distribution for more information.
*
這就是成功安裝的標志。在這個星號后面,就可以輸入Lisp代碼了。比如輸入(print "Hello, World!")
,然后回車,就會輸出"Hello, World!"
。輸入(quit)
或者(exit)
,就會退出SBCL的REPL。后面還有一堆需要在這個REPL里面輸入的命令。每次看到REPL,那就是說的這個東西。
SBCL軟件的配置文件位置為~/.sbclrc
,可以在這個文件中配置SBCL的一些參數。下面安裝過程中會涉及這個文件。
VSCode安裝
VSCode是微軟出品的一個編輯器,可以在這里下載。這個就不需要我多說了,安裝方法也很簡單。
alive插件安裝
Alive插件本身是VSCode的一個插件,可以在插件市場直接搜索安裝。但是Alive的正常運行就不是一個那么簡單的事情了。
Alive的功能依賴于LSP,并不是lao se pi,是Language Server Protocol,是實現通用編輯軟件中不同類型編程語言的語法分析和自動補全的協議。
所以,我們需要安裝一個LSP的實現,這個實現就是alive-lsp。那么Common Lisp的軟件包怎么管理呢?優雅的Common Lisp的軟件包管理工具就是quicklisp。
quicklisp安裝
- 下載
quicklisp.lisp
文件,可以在這里找到,具體的下載鏈接是這里,另存在一個目錄下,比如~/Downloads
。 - 在這個目錄中打開終端,或者打開終端,切換到第一步的目錄。
- 輸入
sbcl --load quicklisp.lisp
,然后就會進入SBCL的REPL。 - 輸入
(quicklisp-quickstart:install)
,然后就會開始安裝quicklisp。 - 安裝完成之后,輸入
(ql:add-to-init-file)
,然后就會把quicklisp的初始化代碼加到~/.sbclrc
文件中,這里有一個確認的過程,不要以為不動了,按一下回車就行。 - 輸入
(quit)
,退出SBCL的REPL。
這個過程簡單粗暴。貌似這幾個網站訪問也很正常,不想大型交友網站github那樣,需要上科學技術。
唯一值得一提的是,quicklisp.lisp
文件只有1757行,還真是一個小巧的東西,等我帶上知識先生的帽子,也許我要好好讀一讀這個文件。
在SBCL的配置文件中,quicklisp
加了幾行:
;;; The following lines added by ql:add-to-init-file:
#-quicklisp
(let ((quicklisp-init (merge-pathnames "quicklisp/setup.lisp"(user-homedir-pathname))))(when (probe-file quicklisp-init)(load quicklisp-init)))
quicklisp
會給你的主文件夾下面生成一個~/quicklisp
文件夾。從SBCL的配置文件可以看到,這個文件夾里面有一個setup.lisp
文件,這個文件是quicklisp
的初始化文件,可以用來加載quicklisp
的軟件包。
alive-lsp安裝
這個插件是目前VSCode上可以用的Common Lisp實現,但是這個玩意有兩個問題:
- 不會自動安裝SBCL
- 不會自動安裝alive-lsp
- 自己不在
quicklisp
的軟件庫里
除此之外,這個軟件目前看起來還是挺完美的。
所以,我們需要手動安裝alive-lsp
。不然的話,我們會一次一次看到報錯“MISSING DEPENDENCY USOCKET”之類的。大概一共有四五個缺失的包,每次都要手動安裝,然后重啟VSCode,再次報錯另外一個包,再次手動安裝,再次重啟VSCode……
鑒于我戴了粗魯先生的帽子,智商的缺陷簡直是肉眼可見。在我把上面的過程全部搞了一遍之后,我才想到可能直接安裝alive-lsp可能是我所需要的,然后就發現quicklisp
里面根本沒有alive-lsp
這個包。
(ql:quickload :alive-lsp) ;; 安裝alive-lsp
(ql:system-apropos "alive") ;; 查找alive包
最后,大型交友網站上看到alive-lsp,跑去看了Alive-LSP的文章。好的,這個玩意還需要自己去裝。
倒是也不虧,學會了一個把自己的包弄到quicklisp
里面的方法。
這幾回到前面提到的文件夾~/quicklisp
,這個文件夾里面有一個local-projects
文件夾,把alive-lsp
的文件夾放到這個文件夾里面,然后再次進入SBCL的REPL,輸入(ql:quickload :alive-lsp)
,就會自動安裝alive-lsp
了。
網絡狀態穩定的話,就在這個目錄下使用下面的命令:
C:\Users\<<username>>\quicklisp\local-projects> git clone https://github.com/nobody-famous/alive-lsp.git
要把<<username>>
替換成你的用戶名。
如果網絡不穩定,那么下面的鏈接是alive-lsp
的壓縮包,這個是我用git archive
命令生成的:
git archive --format=zip --output=alive-lsp.zip HEAD
alive-lisp.zip CSDN下載
alive插件使用
Alive插件的安裝就很簡單了,直接在VSCode的插件市場搜索安裝就行。
安裝好了之后,打開一個Lisp文件,然后就會自動啟動alive-lsp
,然后就可以使用LSP的功能了。
比如下面的命令面板里面增加了一個REPL
的標簽,可以直接在這個標簽里面輸入Lisp代碼,然后執行。
一個小工具的實現
這部分部分就不用深入到uiop
或者語法,或者什么SBCL了,只是展示可能性。
這里,實現一個統計軟件行數的工具,整好寫軟件著作權也需要這個東西。
;; lc.lisp
;; 從命令行獲得一個表達式,然后統計這個表達式的文件的行數,列出每個文件的行數,最后列出總行數(require :uiop)(defun get-expr ()"Get the expression to find files, default is *.lisp"(let ((expr (uiop:command-line-arguments)))(if (null expr)"*.lisp"(car expr))))(defun get-files (expr)(uiop/filesystem:directory-files#P"./"expr));; count lines in a file
(defun count-lines (file)(with-open-file (stream file)(loop for line = (read-line stream nil)while linecount line)));; catch count-lines io errors
(defun count-lines-with-error (file)(handler-case(count-lines file)(error (c)(format t "=====~%Error: ~A~%======~%" c)0)));; count lines in files print each number and sum them
(defun main ()(let ((expr (get-expr)))(let ((sum 0))(dolist (file (get-files expr))(let ((lines (count-lines-with-error file)))(format t "~A: ~A~%" file lines)(incf sum lines)))(format t "Total: ~A~%" sum))))
好了這個軟件已經寫完了。接下來就是如何產生一個可執行文件。
;; compile-lc.lisp
;; 產生一個可執行文件
(load "lc.lisp")
(sb-ext:save-lisp-and-die#p"lc.exe":toplevel #'main:executable t)
有了這兩個文件,就可以在這兩個文件所在的目錄下啟動SBCL,然后輸入(load "compile-lc.lisp")
,就會在這個目錄下生成一個lc.exe
文件,這個文件可以在任何地方使用(SBCL對應的平臺)。
或者直接執行sbcl --load compile-lc.lisp
,也會生成一個lc.exe
文件。
CSDN下載命令行工具:代碼行數統計lc
最后就是這個軟件的使用:
(base) PS C:\lisp-revisit> lc
C:/lisp-revisit/compile-helloworld.lisp: 5
C:/lisp-revisit/compile-lc.lisp: 5
C:/lisp-revisit/helloworld.lisp: 17
C:/lisp-revisit/lc.lisp: 39
Total: 66
這也挺不錯的不是嗎?這個跟lc *.lisp
效果是一樣的。
或者,還能統計子目錄:
(base) PS C:\lisp-revisit> lc **/*.lisp
C:/lisp-revisit/.vscode/alive/fasl/tmp.lisp: 5
C:/lisp-revisit/compile-helloworld.lisp: 5
C:/lisp-revisit/compile-lc.lisp: 5
C:/lisp-revisit/helloworld.lisp: 17
C:/lisp-revisit/lc.lisp: 39
Total: 71
這個效果在windows的PowerShell和cmd上都可以使用。
總結
Common Lisp其實挺好用的。
- 使用SBCL作為Common Lisp的實現
- 使用VSCode作為編輯器
- 使用quicklisp作為軟件包管理工具
- 使用alive-lsp作為LSP的實現,配合alive插件
- SBCL可以直接產生可執行文件,無依賴,單文件