newLISP のクロージャ。。。または、破壊的関数の副作用(その2)

 前回の破壊的関数の副作用を使ったクロージャは、如何だったでしょうか?
 今回はその続き。元ネタは、同じく、Closures and Contexts の “Stateful functions using self modifying code” から。

 では、スクリプトです。

(define (add-quote) (letex (_x (args 0)) (quote '_x)))

(define-macro (make-stack)
; (make-stack func lst)
  (letex (_func (args 0)
          _lst (args 1))
    (define (_func x)
      (if-not x (pop '_lst)
        (setf (nth '(1 2 1) _func) (add-quote (append (eval $it) x)))))))

 今回のスクリプトのメインは、もちろん、

(pop '_lst)

 です。不思議でも何でもない?
 実際に動かしてみましょう。

> (make-stack mypop (a b c))
(lambda (x) 
 (if-not x 
  (pop '(a b c)) 
  (setf (nth '(1 2 1) mypop) (add-quote (append (eval $it) x)))))
> 

 関数 mypop が定義され、その中で pop の対象は '(a b c) になります。
 ここで、問題です。'(a b c) の型は何でしょうか? 答えは後ほど。
 続けて実行すると、

> (mypop)
a
> (mypop)
b
> 

 そして、引数にリストを与えると、

> (mypop '(1 2 3))
'(c 1 2 3)
> mypop
(lambda (x) 
 (if-not x 
  (pop '(c 1 2 3)) 
  (setf (nth '(1 2 1) mypop) (add-quote (append (eval $it) x)))))
> (mypop)
c
> (mypop)
1
> (mypop)
2
> 

 こんな感じです。
 さて、先程の質問の解答の前に、pop のマニュアルから、

pop

syntax: (pop list [int-index-1 [int-index-2 … ]])
syntax: (pop list [list-indexes])

syntax: (pop str [int-index [int-length]])

pop を使って、リストから要素を、あるいは文字列から文字を取り去ることができます。
Using pop, elements can be removed from lists and characters from strings.

第一構文では、pop は、list を評価することで得られたリストから要素を取り出します。第二パラメータが存在するなら、int-index の要素が取り出されます。Indexing elements of strings and lists も見て下さい。
In the first syntax, pop extracts an element from the list found by evaluating list.
If a second parameter is present, the element at int-index is extracted and returned. See also Indexing elements of strings and lists.

 もうお判りですね。関数の中にある '(a b c) の型は、quote 式です(笑)。
(type-of は init.lsp に定義してあります。)

> (nth '(1 2 1) mypop)
'(c 1 2 3)
> (type-of (nth '(1 2 1) mypop))
"quote"
> 

 quote 式が評価されてリストになるので pop でき、引数のリストを追加する際には、組込 eval とquote 式に戻すための補助関数 add-quote が必要となるのです。

 さて、今回の破壊的関数の副作用を使ったクロージャは、如何でしょうか?

 あっ、もちろん、文字列も使えます。

> (make-stack mystr "123")
(lambda (x) 
 (if-not x 
  (pop '"123") 
  (setf (nth '(1 2 1) mystr) (add-quote (append (eval $it) x)))))
> (mystr)
"1"
> (mystr)
"2"
> (mystr "abc")
'"3abc"
> mystr
(lambda (x) 
 (if-not x 
  (pop '"3abc") 
  (setf (nth '(1 2 1) mystr) (add-quote (append (eval $it) x)))))
> (mystr)
"3"
> (mystr)
"a"
> (mystr)
"b"
> (mystr)
"c"
> (mystr)
""
> (mystr)
""
>  

 次回は、、、たぶん予想通り?

No comments yet

コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト /  変更 )

Google フォト

Google アカウントを使ってコメントしています。 ログアウト /  変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト /  変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト /  変更 )

%s と連携中

%d人のブロガーが「いいね」をつけました。