newLISP で On Lisp する。。。第2章(その1)

newLISP で On Lisp する。。。第2章(その1)
(この blog は、“short short story または 晴耕雨読な日々”からの引越してきたもの。スクリプトは、newLISP V10.2.1 以降で動作するように書き直しています。)
第1章は如何だったでしょうか? さて、今回は、第2章 関数です。
newLISP も Common Lisp 同様、関数型の言語です。しかし、関数の定義には、defun ではなく define を使います。

> (define (double x) (* 2 x))
(lambda (x) (* 2 x))
> (double 1)
2 

もっとも、defun をマクロで組めば、一見、Common Lisp 風に見えます。
(defun は、newlisp-utility.lspでマクロ定義してあります。)

> (load "newLISP-utility.lsp")
:
> (defun double (x) (* 2 x))
(lambda (x) (* 2 x))
> (double 1)
2

しかし、newLISP は Common Lisp と違って、変数と関数に異なった名前空間はありません。つまり、同じ名前に同時に変数と関数を与えることは出来ません。そのおかげ(?)で、#’(シャープ・クォート)オペレータが要りません。というよりありません。先ほど定義した関数double は、単体で

> double
(lambda (x) (* 2 x)) 

となり、関数としてのオブジェクトが現れます。double が変数で値が入っていれば、その値が現れることになります。もちろん、関数は、λ式で表すことが出来ます。しかも、lambda の代わりに fn が使えます。

> (fn (x) (* x 2))
(lambda (x) (* x 2)) 

そして、

> (double 3)
6
> ((fn (x) (* x 2)) 3)
6 

と、まあ、ここまでは同じですが、前述のように、関数と変数で名前空間が同じですから、シンボルdobule に関数と値を同時に持たせることは出来ません。もちろん、symbol-value なんかもありません。
とはいえ、関数を変数に入れられるという点では同じです。

> (setq x double)
(lambda (x) (* x 2))
> (x 2)
4
>(= x double)
true

#’ も symbol-function も要りませんが、x に double の関数オブジェクトが入っています。
setf も使えます。

> (setf double (fn (x) (* x 2)))
(lambda (x) (* x 2))

当然、関数を引数にも出来ます。

> (+ 1 2)
3
> (apply + '(1 2))
3
> (apply (fn (x y) (+ x y)) '(1 2))
3

くどいですが、#’ も symbol-function も要りません。ありませんから(笑)。
しかし、newLISPでは、

(apply #'+ 1 '(2))
(funcall #'+ 1 2)

はできません。前者は、apply の引数のとり方の違いから、、、
でも、こういう事はできます。

> (apply (curry + 1) '(2))
3

newLISP組込curry は、とても便利で重宝します。
膨大な組込関数も持つ Common Lisp に無いのが不思議なくらいです。
と言っても、マクロで簡単に組めますけどね。
後者は、funcall 自体がない、というより必要がない。
map 系関数も当然あります。といっても、map だけですけど。関数の機能自体は、mapcar と同じです。Common Lisp の map とは、異なります。

> (map (fn (x) (+ x 10)) '(1 2 3))
(11 12 13)
> (map + '(1 2 3) '(10 100 1000))
(11 102 1003)

sort もあります。 当然、#’ は要りません。

> (sort '(1 4 2 5 6 7 3) <)
(1 2 3 4 5 6 7)

 さて、remove-if ですが、newLISP には、ありません? 嘘です、あります。名前が違っているだけです。組込関数clean がそれにあたります。ちなみに、remove-if-not は、組込関数filter に。でも、何故か evenp はありません。定義します。

> (defun evenp (x) (= (& x 1) 0))
(lambda (x) (= (& x 1) 0))
> (define remove-if clean)
clean 
> (remove-if evenp '(1 2 3 4 5 6 7))
(1 3 5 7)

とまあ、こんな感じです。私がマクロを使ってまで、関数定義に defun を使っているのは、上記のように、define は C言語の #define のようにと使い分けたいからです。
さて、our-remove-if の定義ですが、拙作newLISP用ユーティリティ(car、cdr、defun、null が定義してあります)を使えば、 fn を f に置き換え、funcall を外すだけです。

(defun our-remove-if (f lst)
  (if (null lst)
      nil
    (if (f (car lst))
        (our-remove-if f (cdr lst))
      (cons (car lst) (our-remove-if f (cdr lst))))))

早速試してみると、

> (our-remove-if evenp '(1 2 3 4 5 6 7))
(1 3 5 7 nil)

あらら、nil がくっついている。これは、newLISP の仕様なのでしかたありません。あらためて、newLISP用を定義すると、こうなります。

(defun our-remove-if (f lst)
  (if (null lst)
      '()
    (if (f (car lst))
        (our-remove-if f (cdr lst))
      (cons (car lst) (our-remove-if f (cdr lst))))))

なんのことはない、nil を空リストに変えただけです(笑)。

> (our-remove-if evenp '(1 2 3 4 5 6 7))
(1 3 5 7 nil)

ついでに、newLISP だけで記述してみましょう。

(define (our-remove-if f lst)
  (if (not lst)
      '()
    (if (f (first lst))
        (our-remove-if f (rest lst))
      (cons (first lst) (our-remove-if f (rest lst))))))

と、こんな感じ、如何でしょうか?

長くなったので、第2章の残りは次回に。

No comments yet

コメントを残す

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

WordPress.com ロゴ

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

Google フォト

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

Twitter 画像

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

Facebook の写真

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

%s と連携中

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