日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > python >内容正文

python

lisp语言代替python_PLisp: 集成在Python中的LISP语言实现 (1)

發布時間:2023/12/20 python 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 lisp语言代替python_PLisp: 集成在Python中的LISP语言实现 (1) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

["+", ["*", 3, 4], ['*', 5, 6]]

表示LISP的表達式:

(+ (* 3 4) (5 6))

又如,Python表達式:

["let",

[['x', 2],

['y', 3]],

['*', x, y]]

表示LISP的表達式:

(let

((x 2)

(y 3))

(* x y))

解釋的過程,就可以寫成一個Python函數,輸入一個Python表達式,輸出另一個Python表達式。中間可以用副作用來處理IO。

如何實現呢?

首先,求值需要一個符號表,這個任何語言都一樣,記錄變量(或者LISP的符號)對應的值。而LISP的符號表會隨著求值的過程(副作用)而改變。

class Context(UserDict):

def __init__(self, parent=None):

UserDict.__init__(self)

self.parent = parent

Context類表示一個符號表,或者說LISP求值的“上下文”。Context只不過是一個dict而已,輸入符號,對應到值。這個parent稍候解釋,因為context可以嵌套。

然后,每個LISP函數都可以用Python函數表示。定義為由“上下文和參數的笛卡爾積”到python值的映射。簡而言之,每個LISP函數對應的Python函數,除了“普通參數”以外,還要Context作為額外的參數。比如:

def add(context, one, another):

return one + another

# ['+', 1, 2] calls this function and evaluates to 3

這個函數和符號表無關,不讀取符號表,也不改變符號表。

又如:

def _set(context, key, value):

context[key] = value

return value

# ['set', 'x', 40] calls this function and sets symbol 'x' to 40

這是一個“賦值函數”,通過修改符號表,將符號key的對應于value的值。

def _print(context, expr):

print expr

return expr

# ['print', ['quote', 'hello world!']] calls this function and prints "hello world!" to standard output

這個完全依賴求值的副作用,打印輸出。

函數的基本形式就是這樣。

基本的LISP執行環境需要幾個基本的LISP函數。最基本的當然是eval函數了。LISP中,eval的功能是將一個表達式求值。我定義Python函數_eval,為了避免和內置函數eval命名沖突。

def _eval(context, expr): # 輸入expr,求expr的值

if isinstance(expr, str): # 對于符號,查找符號表獲得值

cur_context = context

# 因為符號表可以嵌套,所以迭代查找。

while cur_context is not None:

if expr in cur_context:

return cur_context[expr]

else:

cur_context = cur_context.parent

raise KeyError(expr)

elif isinstance(expr, list): # 對于表,轉換成函數調用。

first, rest = expr[0], expr[1:]

func = _eval(context, first) # 遞歸對第一個元素求值,得到函數。

if getattr(func,"call_by_name",False)==False: # 處理特殊函數。

evrest = [_eval(context, e) for e in rest]

else:

evrest = rest

return func(context, *evrest) # 調用函數,得到返回值

else:

return expr # 對于其他原子,返回其本身。

正好分3個分支,處理了LISP求值的3種情況。

上述代碼提到了“特殊函數”。一般的函數,調用前,要將參數求值,再傳入。如:

(+ (- 9 3) 4)

必須先求出(- 9 3)的值:6,才能傳入"+"函數。

但是,另外一些函數需要“按名傳遞”,即根據某些條件,選擇性地求值。如:

(if (eq (+ 1 1) 2) right wrong)

if函數是條件函數。先求第一個參數的值,如果是真,則求第二個參數的值,第三個參數不求值;如果是假,求第三個參數的值,第二個參數不動。

因此,對于這些特殊的LISP函數,需要在Python函數上做一些標記。我的做法是,在定義函數后,給這些函數設置其call_by_name的值為True。或者用@decorator更簡單。

典型的if函數,定義如下:

@call_by_name

def _if(context, condition, iftrue, iffalse=None):

if _eval(context, condition):

return _eval(context, iftrue)

else:

return _eval(context, iffalse)

@call_by_name內部完成call_by_name=True的賦值工作。而函數體內部,先用_eval函數求第一個參數的值,對于真假兩種情況,分別調用兩個分支。

另一個典型的“按名傳遞”的函數是quote,這個函數避免其內部的符號被求值。LISP中:

(quote abc)

'abc

兩者求值都得到符號abc。由于quote如此常用,因此LISP中有特殊的引號'語法,方便quote函數的應用。

在Python中:

@call_by_name

def quote(context, expr):

return expr

def q(expr):

return ['quote',expr]

quote函數不對expr求值,而直接返回expr。我還定義了Python函數q,類似LISP的',方便書寫。

有了以上基本函數,其實可以編一些簡單的程序了。以下是一個演示。

# 首先,使用之前,要實例化一個Context對象:

default_context = Context()

# 然后,將基本函數加入這個符號表

default_context["eval"] = _eval

default_context["print"] = _print

default_context["quote"] = quote

default_context["set"] = set

default_context["+"] = add

# 最后,用eval函數求值即可。

# 這是Hello world

_eval(default_context, ["print", q("Hello world!")])

# 屏幕上顯示Hello world!

# 賦值語句

_eval(default_context, ["set", q("x"), 5])

# 改變符號表,"x"對應整數5。

# 計算簡單的加法

result = _eval(default_context, ["+", ["+", 1, "x"], 3])

print result

# 輸出9

總結:

通過以上程序,可以看出,這種實現,輸入是完全合法的Python表達式,輸出也是Python表達式。求值僅僅是用Python語言做了Python表達式的處理而已。

根據目前定義的函數,這個“語言”功能還非常簡單;但是,下篇將引入更多函數,使得這個“語言”逐漸趨近于功能完備的程序設計語言。

分享到:

2010-04-20 02:21

瀏覽 3485

評論

總結

以上是生活随笔為你收集整理的lisp语言代替python_PLisp: 集成在Python中的LISP语言实现 (1)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。