發新話題
打印

請問有關LISP的一些問題

請問有關LISP的一些問題

感謝您這個論壇

讓我了解LISP的基礎指令與用法 不瞞您說,這是我的這次作業,LISP是我第一次觸碰

有些問題想請教您


這是題目的要求
Write the functions initialize, push, top, pop, and list-stack to maintain a global stack. These functions should behave:
>( initialize)
nil
>( push ‘foo)
foo
>( push ‘bar)
bar
>( list-stack)
(bar foo)
>( pop)
bar
>( list-stack)
(foo)


下面是我寫的  
(defun initialize ()
(setq x nil)
)
(defun pus (n)
(push n x)
)
(defun po ()
(pop x )
)
(defun list-stack()
(list x )
)

有一些地方不是很了解~   

1.如果依題目的意思  我該如何寫出,與指令PUSH與POP同名的function ??
   (在定義時,不能使用一樣的名稱,所以我改成pus與po)


2.在執行後                         我的括號,會多一圈   (直接使用push pop指令也是會出現)
                >( initialize)
nil
>( pus ‘foo)
(foo)
>( pus ‘bar)
(bar)
>( list-stack)
((bar foo))
>( po)
(bar)
>( list-stack)
((foo))

Symbols(字符)

symbol 就是一串字元,不過這串字元裡面可以使用的字元跟起始的第一個字元是稍有限制的,
但是原則上只要你使用〝大小寫字母、數字、減號(連接符號)〞來混合產生 symbol,應該就不會有問題。
(如果你只有使用使用數字的,並且至多在拿減號當啟始字元,那將會被 Lisp 視為是數字,而不是 symbol 。)

是這個問題嗎?




TOP

我想這個作業的意思可能是,要求不用內建的 PUSH 跟 POP 巨集,並且重新定義 PUSH 跟 POP 指令。
另外題目有說要把它定義改成用來操作某個全域的堆疊,下面姑且把這個堆疊(其實是把串列當堆疊用)定義成  *my-global-stack* (名稱自取,
至於用兩個星號 * 包起來,是為了要提醒我自己那是全域變數)。

在 ; 後面,直到行末都會被視為是註解喔,可以省略掉。
複製內容到剪貼板
代碼:

(DEFVAR *my-global-stack*)  ; 宣告全域變數 *my-global-stack*


(DEFUN initialize ()
    (SETQ *my-global-stack* NIL)     ; 把  *my-global-stack*  設定成 NIL ,也就是空串列 ()
                                  ; 傳回值會是最後一行,也就是上面那行的 NIL 喔。                                                                                
)

(DEFUN push (n)
    (SETQ *my-global-stack* (CONS n *my-global-stack*))   ; 利用 CONS 把  *my-global-stack*  串列的最前方加入 n 並且把整個新的串列設成是 *my-global-stack*
     n    ; 因為題目要求最後要傳回新加入的值,所以就把 n 擺在最後一行當作是傳回值
)


(DEFUN pop ()
    (LET ((first-element (CAR *my-global-stack*) ))    ; 利用 CAR 取出 *my-global-stack* 串列的第一個元素 ,並且把它設成區域變數  first-element
         (SETQ *my-global-stack* (CDR *my-global-stack*))  ; 把 *my-global-stack* 去掉第一個元素,然後把新的串列丟給 *my-global-stack*
         first-element)                                ; 因為題目要求最後要傳回的是第一個元素,所以放在這裡當作是傳回值
)


(DEFUN list-stack()
    *my-global-stack*  ; 傳回整個串列,所以把 *my-global-stack* 當作是傳回值
)
讓它依序去執行如下
複製內容到剪貼板
代碼:
>(initialize)
NIL
到這裡時, *my-global-stack* 可視範圍是全域的這個串列被初始化(給值)成 NIL ,也就是空串列 ()
複製內容到剪貼板
代碼:
>(push 'foo)
FOO
到這裡時,剛剛的 *my-global-stack* 空串列被利用 CONS 加進去 foo ,變成是 (foo) 串列啦,本來是會傳回 (foo) 的,
可是我們在定義函數的最後一行多加了點東西,讓它傳回值變成是一開始丟進來的字符 foo 了,。
複製內容到剪貼板
代碼:
>(push 'bar)
BAR
到這裡的時候, CONS 這個函數又把 BAR 給加到 (FOO) 這個串列的最前面,變成是 (BAR FOO) ,然後指定給 *my-global-stack* ,
然後依照函數定義的最後一行,依然把當初傳入的參數當作是傳回值。
複製內容到剪貼板
代碼:
>(list-stack)
(BAR FOO)
這裡是要列出題目要求的可視範圍是全域 *my-global-stack* 堆疊(其實就是串列拿來當堆疊用而已),所以輸出結果是 (BAR FOO)。
複製內容到剪貼板
代碼:
>(pop)
BAR
取出串列的最前面的一個元素,也就是 BAR 。當然,要把 *my-global-stack* 重設成去掉第一個元素的新串列。
而取出來的 BAR 要擺在最後一行,才會變成是傳回值。
複製內容到剪貼板
代碼:
>(list-stack)
(FOO)
確認一下 *my-global-stack* 現在是蝦咪,所以現在是去掉 BAR 之後,就變成是 (FOO) 了。



而關於 POP 跟 PUSH 名稱重複的問題,我想可能跟實作環境有關,我試過 Allegro Common Lisp 它不讓我複寫已存在的巨集,
可是,改用 Corman Lisp 就讓我用下面的函數定義重新複寫了,所以如果你的實作環境不容許你複寫,也可以把下面定義 PUSH 跟 POP 的
名稱買成是 my-push 跟 my-pop (或是如你原本寫的 pus 跟 po 也都可以)。
其實我對巨集沒有很熟,呵呵,我也是好玩自學而已,也是個新手,
所以以後如果我看完書發現怎樣強制要求用函數重寫巨集,那再多回一篇,呵呵。

多喝水。

TOP

感謝您耐心的教導~~
原來還有這指令 DEFVAR(第一次看見又上到一課)


為了作業看了好多LISP的網站
才知道LISP最大的特色是寫AI人工智慧的部份

水罐問題   過河問題


比較好奇的是
3公升與5公升的水罐  如何裝出4公升的水

我想了一下
1.先將5升裝滿 倒到 3  剩2
2.將3倒出
3.再將5升內的2升 給3升水罐
4.再裝滿5升水罐 到給 3升水罐
就產生4升得水了

想用迴圈的方式來寫
好像也找不出規則
以程式來表達~好像相當困難

還蠻感興趣的~~不知道可以再請教您這個問題嗎?

TOP

我不懂 AI ,以下只是憑感覺隨便哈拉,也不知道可不可行喔。

樹狀結構由根節點 (5 3) 出發 ,然後利用下面六步產生新節點,

有之前重複出現的節點就不儲存(遞迴的終止條件),


左邊值清空 (若左邊值=0,不做此步)
右邊值清空 (若右邊值=0,不做此步)
左邊往右邊倒 (若右邊已滿=3或左邊=0,不做此步)
右邊往左邊倒 (若左邊已滿=5或右邊=0,不做此步)
左邊加水到滿 (若左邊已滿=5,不做此步)
右邊加水到滿 (若右邊已滿=3,不做此步)

把整個樹狀結構找出來,然後在去搜尋 (4  任意值) 的節點裡,

哪一個最靠近根節點?

只是想法,寫起來可能會很冗長吧。

多喝水。

TOP

引用:
原帖由 weiye 於 2006-11-26 12:36 AM 發表


樹狀結構由根節點 (5 3) 出發 ,

有之前重複出現的節點就不儲存(遞迴的終止條件),
這一步受益良多~

還在煩惱怎麼起頭
多謝提醒~
我知道該怎麼開始了

不好意思一直麻煩您^^"

[ 本帖最後由 zinger 於 2006-11-26 09:44 AM 編輯 ]

TOP

That's okay. 放輕鬆,我也沒幫到蝦咪大忙,
我也是學習者,只是下禮拜天(12/03)要考托福了,
沒辦法慢慢寫出來,等考完我在仔細想想,
呵呵,蠻有趣的題目。

多喝水。

TOP

發新話題