寫 Emacs-Lisp 的感覺

2018-01-29 22-54-09 的螢幕擷圖

最近閒來很認真寫 Lisp ,是因為想要把 Lisp 練到日常可取用的地步。

理由是:先設想用 C, Java, VB, C# 等各種語言好了,如果你想寫一段程式,目標是心血來潮想要隨手使用一次電腦的運算能力,結果會發現,雖然原初的動機是想要電腦快點執行運算,可是,卻因為每次手一沾上那些語言,首先就在處理系統架構、甚至軟體工程的問題,等到寫到相關程式處都已經累了,或者,我需要寫相對超量的文字(例如定義一個 class 組織)之後,才使得主要程式進展一行。相對的,當我沾上程式語言的 REPL 環境,首先就可以敲打一小段程式片段,然後立刻執行。

選擇 Emacs 做 Lisp 的程式環境,相對是心裡感受負擔比較小的。開著 Emacs ,對我來說只是開著一個文字編輯器,想打字進去就打字,而若是不想開著,隨手關掉也沒關係。 Emacs 沒有讓我需要特地創建一份專案檔、專案目錄,然後才可以做什麼事情。

於是,我開始像以往寫 Erlang 、寫 Python 那樣,寫著 Lisp ,來處理一段由 Facebook Graph API 擷取的一批符號。

我發現,在 Lisp 語言的思維裡,對環境的未知程度相對是高的、但是這是正常的,因為我不能看 Lisp 的語法集合裡有所謂 for, while 之類的他種語言的基本關鍵字,也就是說,當我想要使用類似 for loop 的機能時,可能第一時間不知道該使用什麼 function 或 macro 。不過,我當下可以自行定義出一個 function 是 for loop 的功能,無傷大雅。在 Lisp 語言中的感覺就是,同一段程式,別人寫或者我寫,都沒錯,沒必要在極小的程式區域裡強調所謂『不要重新製造輪子』的樣的看法。

第二個感覺是,在 Lisp 的精簡語法結構裡面,構思程式的過程則純粹是在閱讀括號中的文字,以及依附於括號所引導出來的結構感受。

第三個,是對於 Emacs 環境的感想。由於 Ctrl-x Ctrl-e 組合按鍵的能力,我可以將遊標停在如圖所示的 strip-empty-string 的定義句末尾,按下上述組合按鍵, Emacs 則提示我:這段程式已經生效了,接著,我可以切換到 buffer *scratch* 去敲打簡單的測試句來做單元測試:例如, (strip-empty-string (list 'hello "" "" 'world "") nil)

Emacs 程式環境相當簡便,但相對來看,沒有編譯資訊讓我早先發現哪一段 Lisp function 還沒有寫好。並且, Emacs-Lisp 的內涵與 ANSI Common Lisp 有些差異:例如,對於陣列、字串的表達與處理方式不同,則要更仔細閱讀二方面的書本,綜合學習。

廣告
張貼在 Uncategorized

Emacs-Lisp parse-iso8601-time-string

由於從 Facebook 取得一段資料,時間標記法使用了 ISO 8601 格式,但在 emacs 24 打 ​​parse-iso8601-time-string 無法運作(回報 void-function ),於是由 emacs load-path 找到 /usr/share/emacs/24.5/lisp/calendar/parse-time.el 對照 emacs GitHub 版本,沒有找到 parse-iso8601-time-string 的定義,於是,設法安裝了 emacs 25 之後,能使用下列句子處理:

(decode-time (parse-iso8601-time-string "2018-01-26T13:33:46+0000"))
 ;; (46 33 13 26 1 2018 5 nil 28800)

另外,在新的 parse-time.el 註解還提到:沒有人把時間文字的處理做得對。

 

張貼在 Uncategorized

2018-01-28 18-22-08 的螢幕擷圖

寫程式來處理許多資料,在我的心態上,漸漸覺得很像藉由打繩結來編織。

一般學過的方法,有一種稱為 top-down ,也就是首先透過提綱挈領,先處理通用層次的架構,在下及每一部細節。另一種稱為 bottom-up ,先做細節,並藉由組織整合細節,而拼出整體。不過,現在我發現最自然的方法,是從中間切入,向上做 bottom-up ,向下做 top-down 。

至於作為職業的工作,公司那些人們都想:太沒有時間了,很急著要大整體的成果。可是,我想,不管怎樣,程式內的編織結構穩固不穩固,都是我自己要做好的。公司的那些抬面上的冠冕堂皇卻虛浮的需求,我管不起。

張貼在 Uncategorized

送出 Http 請求

我很納悶,對於 Http 請求的處理,比較多有的工具是直接與軟體開發整合,而比較少有工具是向著 Http 請求的文件來做處理。

雖然通常 Http 請求的運作是以客戶端程式產生為主要辦法,但是,假設我誠心誠意閱讀了 Htpp RFC 卻發現實作時要順著工具讓腦筋繞個彎,可能是把請求轉曲為一行式並且拆解為 cURL 的參數,或者是夾在其他實作語言上,但是,若我想打開 emacs 並且好好寫幾句 Http 請求的語法,然後按下什麼指令來送出 Http 請求命令,這樣不對嗎?

於是,經過一個晚上的學習及整理,我學到下列事項:

  1. 使用 netcat (nc) 可以進入互動式 (REPL) 操作,寫 Http 請求語法並且執行請求。但是 nc 不處理  HTTPS 。
  2. 安裝 nmap 之後,能使用 ncat --ssl graph.facebook.com 443 之類的指令,處理 HTTPS 。
  3. emacs 有個外掛程式叫做 restclient ,在 restclient-mode 把 Http 請求寫在 buffer 裡並且敲組合按鍵 Ctrl-c Ctrl-c 可以執行請求。不過, restclient 無法識別 `request-line = method SP request-target SP HTTP-version CRLF` 語法(出自 RFC 7230 3.1.1 )。
  4. Facebook Page (粉絲專頁)的影片查詢請求如下:
    GET https://graph.facebook.com/v2.11/<page ID>/videos?limit=<number>
    Authorization: Bearer <Access Token>
    <page ID> 是粉絲專頁的內部代碼,要上 Facebook 查一查。 <number> 限制本批查詢最多取得的影片項目數。 <Access Token>  是權限憑證,可以去 存取權杖偵錯工具 查到。
張貼在 Uncategorized

在 Windows 編譯 roswell

最近由網路消息得知 roswell 這個正在開發中的 Lisp 管理工具,於是認真探討它在 Windows 運作的可能與便利。 roswell 的軟體地位,就像是 Linux 的 apt ,或 Erlang 的 kerl 。

最後確定在 Windows 最簡便的編譯安裝方式就是由 msys2 編譯。

需要的軟體大致是在 msys2 內要安裝 gcc, autoconf, make, mingw32-<arch>-gcc, mingw32-<arch>-make, 以及 curl 等等。

編譯及安裝方式:

$ git clone https://github.com/roswell/roswell.git && cd roswell

$ sh bootstrap

$ ./configure

$ make

$ make winrelease

上述的最後一步,在 make winrelease 之後,除了會產生 .zip 檔案以外,還會留下一個 roswell/ 目錄,裡頭放著符合在 Windows 運作的 ros.exe 及相關 .lisp, .ros 檔案。

於是,如果想要安裝到 D:\temp 目錄,則接著用下列指令。

$ mkdir -p /d/temp && cp -rf roswell/* /d/temp

 

張貼在 Lsip, Uncategorized

三則讀後小感

小感 #1

讀 1998 年 John Hughes 談 Haskell Monad 與 Arrow 的文章,其中提到對於 Monad 的解釋

class Monad m where
return :: a -> m a
(>>=)  :: m a -> (a -> m b) -> m b

說:這意思是,做為定義中的參數 m 這個資料類型是個 Monad ,透過 m 可以構成一組結構,格式為 m a 或者 m b ,意思是 m 表示一種執行完之後能傳回資料類型是 a 或 b 的一種計算行為。

哇賽,這定義非常是個 functional 風味的定義。如在 C 語言所看到許多稱為「函式」的那些 function ,它們的模式正可表達為 m a ,做完一些動作之後會跑出資料類型為 a 的傳回值。於是,在 Haskell 中看到的函數定義為 putStrLn :: String -> IO () ,所以 putStrLn “hello,world" :: IO () 的意思是列印一段文字的程式是一套計算動作,做完之後傳回 () (一對括號,稱為 unit ,基本單位的意思)。

小感 #2

讀 “An Introduction to Programming in Emacs Lisp" ,介紹 Emacs 這套編輯器。文件開頭說,可以把 Emacs 認知為可擴充的計算環境,可以把 Emacs Lisp 當作是一套獨立的程式語言。

小感 #3

同上一本書,簡介 Lisp 的意義也很有味道: LISt Processing ,列表處理。

回想 Lisp 程式都是長為一套原始的結構:有個開頭的左括號,並且有個結尾的右括號,並且可以以空格為分隔符號,安插任何數量的辭彙進去二括號之間。這樣的結構稱為 list ,而 list 之內的任何辭彙也可以是 list 。 Lisp 的左右括號有明確的分隔意義,不但可以分隔前一句與後一句,並且可以區別 parent list 與 child list 。

於是,我聯想到的是,組合語言的結構也是這麼簡單。

張貼在 Haskell, Lsip

Haskell ($) 運算符號

在 GHCi 打 `:t ($)` 可見到下列結果

Prelude> :t ($)
($) :: (a -> b) -> a -> b

簡單看,就是把函數套上參數而已。不過,運算的內涵, ($) 是一個比起 (+), (*) 等數學運算符號來,優先權更低的運算符號。

試想,我們所知道的數學運算符號, (*) 比 (+) 優先:

3 + 2 * 4 = 3 + (2 * 4)

那麼,在 Haskell 所見的 ($) 優先等級最低,則在 ($) 左右邊的算式,形同分別把整段加上括號。所以以下二行是相同意思:

succ $ 3 * 2
(succ) (3 * 2)

並且,以下二行也是相同意思:

take 3 $ repeat 3
(take 3) (repeat 3)

於是,如下例,可以運用 let-in 語法與 ($) 運算,寫結構複雜的句子而不必加上括號:

Prelude> :{
Prelude| let n = succ $ 3 * 2
Prelude| in take n $ repeat n
Prelude| :}
[7,7,7,7,7,7,7]

結語

($) 運算符號為最低優先等級的運算符號,並且運算順序為右方結合。

張貼在 Haskell | 標記 ,