讀取-求值-輸出循環
![]() | 此條目包含過多行話或專業術語,可能需要簡化或提出進一步解釋。 (2018年4月20日) |
此條目沒有列出任何參考或來源。 (2018年4月20日) |
「讀取-求值-輸出」循環(英語:Read-Eval-Print Loop,簡稱REPL),也被稱做交互式頂層構件(英語:interactive toplevel),是一個簡單的,交互式的編程環境。這個詞常常用於指代一個Lisp的交互式開發環境,也能指代命令行的模式。
概述
「讀入-求值-輸出」循環 的名字來自於以下幾個Lisp用來實現這種機制的內置函數:
- 讀入函數接收一個來自於用戶的表達式,將其解析成數據結構並存入記憶體。例如,用戶可能會輸入一個s-表達式
(+ 1 2 3)
,這句話會被解析成一個包含四個元素的鍊表。 - 求值函數 負責處理內部的數據結構並對其求值。在Lisp中,求一個以函數名開頭的s-表達式意味着對接下來的參數調用那個函數。所以函數"
+
"被在參數1 2 3
上調用,產生結果6
。 - 輸出函數接受求值結果,並將其呈現給用戶。儘管當前的結果「
6
」並不具有複雜的格式,但如果是一個較為複雜的表達式,那麼它將會被精心處理,以便於更方便地被理解。
REPL使得探索性的編程和調試更加便捷,因為「讀取-求值-輸出」循環通常會比經典的「編輯-編譯-運行-調試」模式要更快。
優點
REPL對於學習一門新的程式語言具有很大的幫助,因為它能立刻對初學者做出回應。許多工具集和程式語言使用REPL研究算法、進行調試,比如MATLAB,ROOT(頁面存檔備份,存於互聯網檔案館),SciPy和IPython。Python的doctest模塊能夠通過捕捉自身REPL命令行的輸出使測試代碼更容易地進行。
由於 print
函數輸出的數據格式(字符串)與用戶輸入的數據格式(字符串)相同,大多數輸出的結果也可以被帶回到 read
函數作為輸入。然而,有的時候輸出的結果只能代表求值結果而不是求值結果本身,比如一個socket句柄或一些類的實例。比如在Python中使用 <__模块名__.类名 实例名>
這種形式來代表一個實例本身,在Common Lisp當中就使用 #<whatever>
的形式。而在CLIM,SLIME以及Symbolics Lisp Machine的REPL卻有辦法讀取很難被完全字符串化的這些對象。他們記錄被輸出過的對象,之後當代碼被讀取時,這些對象能夠被解析並重新被使用。
實現
為了實現一個 Lisp REPL,只需要實現這三個函數和一個不停輪詢的函數即可(當然,求值函數的實現是最為複雜的,因為它在內部要實現像 car
與 +
的原始函數以及像if
一樣的特殊操作符)。這些工作完成了之後,一個基本的REPL就可以用如下的簡單形式表達:(loop (print (eval (read))))
。
一種實現eval
的方式就是實現一個遞歸處理抽象語法樹(該語法樹被 read
函數創建)的函數。另一種可行的方法是將這個抽象語法樹編譯為機器碼並執行。
主要的REPL程式語言環境
APL、BASIC、Clojure、F#、Haskell、J、Julia、Perl、PHP、Prolog、Python、R、Ruby、Scala、Smalltalk、Standard ML、Swift、Tcl、Javascript、Java(自JDK 9起)