トップページ⇒tech
1001コメント355KB

CommonLisp Scheme Part12

■ このスレッドは過去ログ倉庫に格納されています
0001デフォルトの名無しさんNGNG
過去スレ
Part1: http://piza2.2ch.net/tech/kako/987/987169286.html
Part2: http://pc.2ch.net/tech/kako/1002/10025/1002584344.html
Part3: http://pc.2ch.net/tech/kako/1008/10082/1008220265.html
Part4: http://pc.2ch.net/tech/kako/1016/10162/1016211619.html
Part5: http://pc3.2ch.net/tech/kako/1023/10230/1023091882.html
Part6: http://pc3.2ch.net/tech/kako/1031/10315/1031560687.html
Part7: http://pc5.2ch.net/tech/kako/1042/10421/1042167213.html
Part8: http://pc5.2ch.net/tech/kako/1058/10582/1058263391.html
Part9: http://pc2.2ch.net/test/read.cgi/tech/1069594582/
Part10: http://pc5.2ch.net/test/read.cgi/tech/1075630259/
Part11: http://pc5.2ch.net/test/read.cgi/tech/1091456033/

関連リンクは>>2-10あたり
0232デフォルトの名無しさんNGNG
"The Little Schemer"を読んでいると、atom?が重要ということが
わかりました。しかし、Gaucheにはないようなのですが、何か、
深い理由でもあるのでしょうか?

作るならこう?
(define (atom? x)
(and (not (pair? x))(not (null? x))))
0233デフォルトの名無しさんNGNG
空リストはアトム
0234デフォルトの名無しさんNGNG
define-syntaxってdefine-macroと違って書いたものがそのまま展開される
と思うんですが、define-macroみたいにメタな場合分けってできないんでしょうか。
だとしたらパワーが全然違うと思うんですけど。
0235デフォルトの名無しさんNGNG
gauche には atom? じゃなくて
同じ機能の not-pair? があります。
0236229NGNG
>>231
Personal版をダウソしてみた。
時々出るダイアログが烈しくウザ!
0237デフォルトの名無しさんNGNG
>>231
LW4.3との比較であればBill Clementson's Blogにベンチマーク採ったの載ってるよ。
LW4.3からLW4.4でどの程度高速化されたか早く知りたい。買わないけど。
0238デフォルトの名無しさんNGNG
>>234
世の中にはdefine-syntaxだけでquasiquoteの展開を書く人もいるわけだが....(汗
やっぱりsyntax-caseかdefine-macroがないとつらいよね。
0239デフォルトの名無しさんNGNG
>>233 >>235
空リストはアトムなんですね。
ということで、not-pair? ってのでいいんですね。ありがとうございました。
0240デフォルトの名無しさんNGNG
schemeにatomは無いんじゃなかったっけ
0241デフォルトの名無しさんNGNG
atom 型ていうのはないですね、仕様上。
非共有性に基づいて型を定義している以上、当然ではあるけれども。
0242デフォルトの名無しさんNGNG
ACL7.0 EnterpriseがUS$99.00って・・・学生ウラヤマスィ。
研究室遊びに行って後輩捕まえて代わりに買ってもらおうかな(w
0243デフォルトの名無しさんNGNG
>>242
学生じゃなくても個人ユースならその値段で売って欲しいぞ。
0244デフォルトの名無しさんNGNG
憶測だけど、完成したアプリはたぶん無制限に配布してはいけないのだろうな。
0245デフォルトの名無しさんNGNG
CLOSを常用してる人って、いるんですか?
同名のメソッドは引数を合わせないといけないので、
パッケージを分けたくない時は、javaとかでいう抽象クラス名みたいなものを
プレフィクスに付けたりしないと名前が被りますよね。
メッセージ伝達モデルのほうが型ごとに名前空間を分離できるし、
タイプ量も減って手軽だと思うんですけど、
普段は、そういうオブジェクトシステムを使ってるって人いないですか?
0246デフォルトの名無しさんNGNG
>>245
>>同名のメソッドは引数を合わせないといけないので、

何言ってんのあんた。
0247デフォルトの名無しさんNGNG
>>246
パラメータリストを整合的にしないといけないということです。
メッセージ伝達モデルだと、関係の無いクラスで
同名の引数の数が違うメソッドが定義されていないかなどといったことは
気にしませんから、それがわずらわしく感じないかということを言いたかったのですが。
0248デフォルトの名無しさんNGNG
>>247
言いたいことがよく判らない。
簡単なものでいいから、具体例を出して説明して頂けないか。
0249デフォルトの名無しさんNGNG
お隣のスレの80ですか?
0250247NGNG
構造体のメンバの参照でも同じことですが、
変数名 . 動詞or名詞
と普通のオブジェクト指向言語では書けるところが、
(パッケージ名:動詞 変数名)
あるいは、
(型名-動詞or名詞 変数名)
となって、タイプ量が増えて面倒だと言いたいだけです。
普通はパッケージ名は書かないのかもしれませんが、
複数のパッケージからインポートして、それぞれに整合的でないメソッドが
含まれている場合、シンボルのインポートを諦めるか、
メソッド名に基底クラス名等のプレフィクスを付けるか、
全く違う名前に変更してユニーク性を確保する羽目になります。
型の名前やパッケージ名が繰り返し書かれると、
情報の多重化になりますから、名前を変更する時も面倒です。
本当に複数の引数の型でディスパッチしたい状況というのは少なそうですから、
この負担が割りにあってるかは疑問です。
日常的に使いたくなるのはメッセージ伝達モデルの方であり、
総称関数を使いたい状況の方がむしろ特殊じゃないかと。

オブジェクトをキーワードやシンボルを引数に取るクロージャにして
(funcall 変数名 '動詞)
Schemeなら単に (変数名 '動詞)
と書けるようなオブジェクトシステムを実装するのは簡単なので
やってる人は結構いるんじゃないかと思ったのですが。

総称関数モデルとメッセージ伝達モデルのトレードオフくらい
ここの人は分かってると思ったので、単に
「メッセージ伝達モデルの奴が欲しいんだけど、いいのない?」
みたいな聞き方でも充分通じると思ったのですが。
0251デフォルトの名無しさんNGNG
で、結局のところ何を聞きたいわけですか?
0252デフォルトの名無しさんNGNG
>>250
いや、だから具体例を出してくれはしないだろうか。
何で generic function の名前に型名をつける必要があるのか理解できない。
パッケージについても、まあ名前の衝突はありうるけれども、
それがメッセージ伝達型だと何で解消できるの?
それは総称関数モデルの問題じゃなくて、
Common Lisp のパッケージシステムの問題じゃなかろうか。

取りあえず、何というか、手続きの総称化ということについて
よく判っていないのではないかという印象を受けた。

ちなみにメッセージ伝達モデルの oo については
Paul Graham の"ANSI Common LIsp" で例題として実装している。
まあ、Common Lisp でわざわざ oo 実装するやつも少ないので、
Scheme の方で探して、気に入ったのがあったら移植でもしたらいいんじゃない?
CLOS like なのしか思い浮かばないんで、紹介は出来ないけど。
0253デフォルトの名無しさんNGNG
> 取りあえず、何というか、手続きの総称化ということについて
> よく判っていないのではないかという印象を受けた。

俺も。何か気の毒だからちゃんと勉強して出直すことを期待。
0254デフォルトの名無しさんNGNG
型名をprefixにつけるなんて間抜けすぎ。最近ではOO界でもDuck Typingが
推奨されてるのに。
0255デフォルトの名無しさんNGNG
prefix が問題ではなくて、こんな感じにすると、
1番目の add と2番目の add の引数が違うのでだめじゃんってのが問題なんじゃない
(defclass surface ()
((poins :initform () :accessor points)))
(defclass point ()
((x :initarg :x :accessor x)
(y :initarg :y :accessor y)))
(defmethod add ((surface surface) (point point))
(push point (points surface)))
(defmethod add ((surface surface) x y)
(add surface (make-instance 'point :x x :y y)))
0256デフォルトの名無しさんNGNG
>>255 俺もその手の、同じ名前でラムダリストが違う場合を言いたいのだろうなと思った。
あと、それとは逆でラムダリストはたまたま合同になるけど、処理の内容が
ほとんど別のことを表しているときはどうだろう。なんとなく気持が悪くない?
パッケージで分割できればいいけど。
0257デフォルトの名無しさんNGNG
>>255
ん?
今 Common Lisp の処理系が手元にないので Gauche で試したけど、
それ、ちゃんと動くよ? CLOS だと駄目だったっけ?
0258デフォルトの名無しさんNGNG
CLOSはラムダリストが同じじゃないとダメ。
stklosとかgaucheは制限が緩い。

CLOSでだめなのは最適化かなんかの都合なの?
0259247NGNG
>>255
>>256
言いたいのはそういうことです。良い例をありがとうございます。

>>258
それは知りませんでした・・・
てっきり回避不可能に近い制限なのだろうと思ってたので。
その仕様だと、効率を除けばデメリットは無いですよね・・・
gaucheでいろいろ試してみます。
0260234NGNG
>>238
quasiquoteの展開ってこういうのじゃ駄目でしょうか?

(define-syntax qq
(syntax-rules (uq)
((_ ()) '())
((_ (uq a)) a)
((_ (a . b)) (cons (qq a) (qq b)))
((_ a) 'a)
))

理論上は define-syntaxでなんでも書けるらしいですね。
なにか面白いマクロネタありませんかね。
0261234NGNG
後 quasiquoteを使った quoteの定義

(define-syntax q
(syntax-rules (uq)
((_ ()) (qq ()))
((_ (uq a)) (list (qq uq) (q a)))
((_ (a . b)) (cons (q a) (q b)))
((_ a) (qq a))
))

うーん、なんか見落してる気がする。
0262234NGNG
あ、unquoteの時は計算結果に置き変えないといけないんですか。
evalじゃないだろうし、どうやったらいいか想像できないです。

unquoteがマクロ展開時に計算されるっていうのは、処理系がマクロ展開時、実行時
の2ステップに分かれていれば意味あると思うんですけど、そうでない場合
なにか意味あるんでしょうか? 計算結果は変わらないですよね。
0263sageNGNG
こんな処理をする手続きrember* をつくりました。
  (rember* 'b '(a b c (a b c))) => (a c (a c))
これをcall/ccを使った大域脱出させたいです。
  (rember* 'b '(a b c END d (a b c)) => (a c END (a b c))
  
しかし下のコードでは希望する動きをしません。  
  => (rember* 'b (a c END (a c))

下のコードをつかって、うまく脱出する方法はあるでしょうか?

(define rember*
(lambda (a l)
(call/cc (lambda (escape)
(cond ((null? l) '())
((not-pair? (car l))
(cond ((eq? (car l) a)
(rember* a (cdr l)))
((eq? (car l) 'END)(escape (cons 'END '())))
(else (cons (car l) (rember* a (cdr l))))))
(else (cons (rember* a (car l))
(rember* a (cdr l)))))))))

0264sageNGNG
>>263
見やすく書き込む方法はあるのでしょうか?
2ちゃんねる初心者です(^^;
0265デフォルトの名無しさんNGNG
それ以前に、仕様を明確に定義しろよ。
なんとなくは分かるが、前半の例と後半のコードが一致しないし、typo も多いし、
正しくはどうやりたいのかがみえない。
0266デフォルトの名無しさんNGNG
>>264
とりあえず、下げたいのなら、sageはメール欄に書こうな。
0267デフォルトの名無しさんNGNG
>>264
` ' (半角スペース) を ` ' に置換する.
0268デフォルトの名無しさんNGNG
call/ccを使う必要ないんじゃ?
0269デフォルトの名無しさんNGNG
ENDは特別扱いなのか?
何がしたいのかわかんねえよヴォケ
0270デフォルトの名無しさんNGNG
>>263
説明不足でご迷惑かけました。改めて
手続きrember* a l は、リスト「l」から再帰的に「a」を除くものです。
(rember* 'b '(a b c (a b c) ((a) (b) (c))))
; -> (a c (a c) ((a)()(c)))
-------------------
(use srfi-1)
(define rember*
 (lambda (a l)
  (cond ((null? l) '())
        ((not-pair? (car l))
         (cond ((eq? (car l) a)
                (rember* a (cdr l)))
               (else (cons (car l) (rember* a (cdr l))))))
        (else (cons (rember* a (car l))
                    (rember* a (cdr l)))))))
0271デフォルトの名無しさんNGNG
>>270
実際にやりたい処理は次です。
『'END にぶつかったならば、処理を終了して、最後に"LAST" を付け
たリストを得る』
 具体的には、下のような処理です。
(rember2* 'b '(a b c (a b c END d e) ((a) (b) (c))))
;-> (a c (a c "LAST") ((a) (b) (c)))

こういう処理は、270以外のやり方の方がいいのかもしれません。
ただ、270は「The Little Schemer」で紹介されている定石なので、
270から発展させた解決策をしりたいです。
アドバイスをお願いします。
PS >>268 call/cc はいらないですね。ども。

0272デフォルトの名無しさんNGNG
>>271
下のrember2* では、....((a)(b)(c))) にはなりません。再帰がとまらないのです。
(rember2* 'b '(a b c (a b c END d e) ((a) (b) (c))))
;-> (a c (a c "LAST") ((a) () (c)))

(define rember2*
  (lambda (a l)
    (cond ((null? l) '())
          ((not-pair? (car l))
           (cond ((eq? (car l) a)
                  (rember2* a (cdr l)))
                 ((eq? (car l) 'END)
                  (cons "LAST" '()))
                 (else (cons (car l) (rember2* a (cdr l))))))
          (else (cons (rember2* a (car l))
                      (rember2* a (cdr l)))))))

0273デフォルトの名無しさんNGNG
汚ないけど一応動くかも

(define rember2*
(lambda (a l)
(letrec ((iter (lambda (a l c)
(cond ((null? l) (c #t l))
((not-pair? (car l))
(cond ((eq? (car l) a)
(iter a (cdr l) c))
((eq? (car l) 'END)
(c #f '("LAST")))
(else (iter a (cdr l) (lambda (b ll) (c b (cons (car l) ll)))))))
(else (iter a (car l) (lambda (b ll) (if b (c #t (cons ll (iter a (cdr l) (lambda (b l) l)))) (c #f (cons ll (cdr l)))))))
))))
(iter a l (lambda (b l) l))
)))
0274273NGNG
長い行は
(else (iter a (car l) (lambda (b ll) (c b (cons ll (if b (rember2* a (cdr l)) (cdr l)))))))
の方が綺麗かな。
0275(define (´∀`) 'マターリ)NGNG
(define (rember* a l)
  (let loop ((l l) (cont (lambda (x) x)) (end (lambda (x) x)))
    (cond ((null? l) (cont l))
          ((eq? (car l) a) (loop (cdr l) cont end))
          ((eq? (car l) 'END) (end (list "LAST")))
          ((list? (car l))
           (loop (car l)
                 (lambda (x) (loop (cdr l)
                                   (lambda (y) (cont (cons x y)))
                                   (lambda (y) (end (cons x y)))))
                 (lambda (x) (end (cons x (cdr l))))))
          (else (loop (cdr l)
                      (lambda (x) (cont (cons (car l) x)))
                      (lambda (x) (end (cons (car l) x))))))))
0276デフォルトの名無しさんNGNG
さいきんちらほらとム板スレで出てくるIoって言語は
LISPの思想に近いらしく、基本はすべて
object method(...)
らしい。ただ、これとは別に演算子もある。
これはこれでかなりまとも(というか普通)な発想だと思う。
また、objectとmethodに対するありがちな.(ドット)連結を廃止して、
symbol symbolという並びをobject methodに簡略化した点でも評価できる。
methodの引数をそのまま関数引数形式にしたのもC/C++勢力にも受けると思う。

さて、
object method1(...) method2(...)
とすればmethod1の結果のオブジェクトに対してmethod2を連鎖適用できる。
この書き方はC/C++でもほぼ同じだから馴染み深い。

LISP(Scheme)の関数は適用がいつも先頭引数という決まりなので
(method2 (method1 object ...))
と、見た目の順序が逆になる。
((object method1 ...) method2 ...)
という風にも書けないことはないが、
細工をしない限り機能しない。(言い換えればLISPの一般的な書き方ではない。)
※ここでいう細工とは、マクロで専用インタフェースを書くか、
自分でメソッドディスパッチする必要があるという事。

ここで思うことは、主流のオブジェクト指向をする際、
この連鎖適用における順序の違いが思考の妨げになるのではないかということ。
今主流の言語は(関数型でさえも) object method形式だから、
LISP(Scheme)でやろうとする場合、専用の頭が必要になる。
0277デフォルトの名無しさんNGNG
そもそもオブジェクトとはどういう概念なのか説明してくれないか。
0278デフォルトの名無しさんNGNG
そこでArcですよ
0279デフォルトの名無しさんNGNG
ではIoの構文はどうか。
Ioではifなどの構文もメソッドであるという。
メソッドというからには何かのオブジェクトに従属するはずだが、
Ioでは暗黙のrootオブジェクト(Lobby)という概念を作ってカバーしたらしい。

例えばif式だと
if(test_part, then_part, else_part)
という書き方になる。

構文要素をカンマで区切る辺りが少し不気味な気がするが、
LISPの怒濤の括弧ほどショッキングではないのかもしれない。
ここで注目したいのは、Ioの構文はメソッドであるため、
どうやらマクロの様な特殊な機構は必要ないらしい。
ただし肝心の評価順序の制御がどういう原理で行われるのか正確には不明。
(thisMessage という機構でえらい騒ぎになるらしい)
構文に対する特殊化を先送りしているだけにすぎない様な気もするが、
表向きメソッドとして統一した事に意義があるのだと思う。

ただ、構文をメソッドとして定義するということは、マクロの様に展開する機会がなく、
毎回作成した専用構文の解釈を行うということになるので、
実行効率はかなり犠牲なるはず。
マクロ的な展開機構が導入されれば解決するのかもしれないが、
その辺はかなり道のり遠そうである。
この辺を追求していくとIoの雲行きが怪しくなってくる。
ともあれ、実用性や効率に目をつむればかなり洗練された言語であることは間違いない。
0280デフォルトの名無しさんNGNG
Ioスレでやれ
0281デフォルトの名無しさんNGNG
いや、別にIo使う気ないけど。
LISPでもシンプルなオブジェクト指向ってできねーのかなと思って。
似た言語の筈のIoと何が違うのかなって知識の整理。
要はIoの構文はマクロの代わりにメッセージという裏技でカバーってことね。
基本概念違うから(CLOS程大きいシステムならともかく)適用してもあんま旨みがない。
0282デフォルトの名無しさんNGNG
構文なんて些細な違いにすぎないんだが
0283デフォルトの名無しさんNGNG
>>282
おれは逆にえらい違いだと思ってるわけで。

object method1(...) method2(...)
に対して
(method2 (method1 object ...)...)
((object method1 ...) method2 ...)
やっぱ連鎖適用で括弧がネストするのは美しくないなと。


Ioでは現状おまけみたいなものだけど、
連鎖適用とメッセージを駆使すれば適当な構文が書けたりする。
if (test_part) then (then_part) else (else_part)
とか。
たぶんこれ遅いんだろうなあ。
0284デフォルトの名無しさんNGNG
ここは281のメモ帳じゃない。
0285デフォルトの名無しさんNGNG
数学で、f(g(x), h(y))っていう書き方があるでしょ、
これはLispの表記法と一緒だよね。おれはこの部分でLispに違和感を感じたことはない。
0286デフォルトの名無しさんNGNG
普通に(f (g x))と連鎖適用で括弧がネストするが?
0287デフォルトの名無しさんNGNG
CommonLispにloopみたいなオブジェクト指向用の汎用マクロ作ってもらえ。
0288デフォルトの名無しさんNGNG
いやそうだけど、括弧がネストするのが思考のさまたげにはなりにくいのでは
ないかい? 算数や数学でこの表記法に慣れているから。
0289デフォルトの名無しさんNGNG
いや、数学の話じゃなくて、一般的になりつつある
object methodの書式の話なわけで。
Ioの
object method1(...) method2(...)
はC++では
object->method2()->method2()
ね。
無理解を装ってるだけだろうけど。
0290デフォルトの名無しさんNGNG
上のC++の例は
object->method1(...)->method2(...)
の間違いね。
LISPの場合これぐらいならフロントエンド書けばおしまいだけどね。
0291デフォルトの名無しさんNGNG
いや、無理解を装っているわけじゃないよ。
object methodの書式の話だとして、
CLOSではメソッドが属すジェネリック関数が、普通の関数と同じ書式で呼び出せる
ということに利点を感じて、(gf1 (gf2 obj0) (gf3 obj1))なんて感じの表記に
したのでしょう。

それが主流から外れているというのなら、ふ〜んというしかないけど。
全般的に劣った表記体系かといえば、そうは思わないという話。
0292デフォルトの名無しさんNGNG
だらだら書く場合は、前に戻って関数挿入するのが面倒。
んで、その関数の引数について、こんどは右端までいかないと書けない。
これが主流のオブジェクト指向に向いてないという根拠の1つ。
数アクションぐらい余計に負担が掛かる。
0293デフォルトの名無しさんNGNG
そっ、それは…、エディタがなんとかするということで、妥協できませんか。
すまん、もうねるぽ。
0294デフォルトの名無しさんNGNG
>>292
そんな表面的な部分だけ取り上げて得意気になられてもなあ
0295デフォルトの名無しさんNGNG
どこが表面的なんだか。
根幹に関わる。
0296デフォルトの名無しさんNGNG
そのうちカッコを入力するのも面倒になり、
キーボードを打つのも面倒になるのだろうな。
0297デフォルトの名無しさんNGNG
それこそCでオブジェクト指向できると言い張るぐらい滑稽。
0298デフォルトの名無しさんNGNG
機械語でオブジェクト指向ってできないの?
0299デフォルトの名無しさんNGNG
やりたかったらやりなさいよ。
でもつまらないよ。
0300デフォルトの名無しさんNGNG
>>295
Lisp にとって、構文の問題は「表面的」なんだよ。
macro 書けば解決するから。
0301300NGNG
ごめん、へんなこと書いた。忘れて。
0302デフォルトの名無しさんNGNG
「o君、mしてね」というのだけが、オブジェクト指向じゃなかろうに、
「mしてね、o君」というのでも、オブジェクト指向なんじゃないの、
S式は、後者に適しているというだけなんじゃないの。
0303デフォルトの名無しさんNGNG
オブジェクト指向にするとどんな利点があるのか分からない。
0304デフォルトの名無しさんNGNG
>>302
o君、m1してね p1とp2で その後 m2してね p3とp4で

後でm2してね、最初にm1してね、o君、 p1とp2で ところでm2の件だけどp3とp4使ってね


わかりますか?
0305デフォルトの名無しさんNGNG
つまり

前者が
object method1(p1, p2) method2(p3, p4)

後者が
(method2 (method1 object p1 p2) p3 p4)

なわけです。
後者は文章にするのも大変だということがわかりますか?
0306デフォルトの名無しさんNGNG
オブジェクト指向とかゆうより前置記法が嫌なんだろ。
↓でも参考にして好きなようにすれば?
ttp://www.cliki.net/infix
ttp://lambda.s55.xrea.com/20040325.html
0307デフォルトの名無しさんNGNG
オブジェクト指向は幻想
0308デフォルトの名無しさんNGNG
後者の場合、methodが続くと大変なことになります。

最後にmnするんだけど、そのまえにmn-1してね、・・・
最初にm1してね、o君、
m1の件はp1とp2で。
m2の件ではp3とp4、・・・
mnの件は・・・なんだっけ?

一般人の短期記憶スタックは6〜8ネストぐらいが限界だとどこかで読んだ事がありますが、
口頭で言われた場合、理解できるでしょうか。
0309デフォルトの名無しさんNGNG
>>306
当然ながらフロントエンドについては考えてるよ。
0310デフォルトの名無しさんNGNG
(define-syntax chain
  (syntax-rules ()
    ((_ obj) obj)
    ((_ obj (m . args) . more)
      (chain (m obj . args) . more))))

(chain obj (method1 p1 p2) (method2 p3 p4))) -> (method2 (method1 obj p1 p2) p3 p4)
0311デフォルトの名無しさんNGNG
>>308
そんなにダラダラ書いたらどんな記法であろうと分かりにくくなるのは当然だろ
なんのためのインデント、なんのための一時変数、なんのための括弧、なんのt(ry
要はあんたが前置記法では分かりにくいってだけでしょ
あんたに理解しづらいからといって他の人もそうであるとは限らない
0312デフォルトの名無しさんNGNG
ネストが深くなるとインデントがつがつ入って
横長になっちゃって見辛い、てのはあるかなあ。
適当に切り分ければいいだけの話だけど。

でも、たとえばこんな感じの関数書けば、
(define cascade
  (lambda (x . fs)
    (fold (lambda (f knil) (f knil)) x fs)))
こんな感じに書けるけれど、
(cascade (iota 10) (filter$ even?) (fold$ + 0)) => 20
ちょっとややこしいのになるとあんまり書きやすいと感じなかったなあ。
上記の、インデントの関係で読みやすくはあったけど。

どうしてかな、て考えてみると、自分の場合はまず、結局最後は何やるの?
ていうのを考えて、それに渡す値はどうするの?
更にそれに渡す値は……みたいな感じの思考パターンで考えることが多いみたい。
元の値から結論に向って値を下げ渡していく感じじゃなくて、
最初に結論ありきでそれに向って差し戻していくイメージっていうか。上手く言えないけど。

実際のところ、最終的に何をしたいのかていうのは、
その途中の経路よりははっきりしていることが多いと思うので、
それをまず書いちゃって、それに渡す値を作るところは適当に副関数に切り分けておいて、
後からそれを別立てで書いたほうが思考の流れに沿って作業できないかなあ。

一方で充分にライブラリが揃っていて、後はそれを糊付けしていけばいい、
てところまで状態が整っているならば、obj->metha->methb->...
みたいな書き方のほうが楽かもしれない。

結局のところ、問題の質や切り分け方で、
それに適った思考過程、対応するような記法は変わってくるだろうから、
どういう記法が優れているか、ていう単純な話ではなくて、
それぞれの記法はどのように問題を切り分けるのに向いているか、てことじゃないかなあ。
0313デフォルトの名無しさんNGNG
だらだら書いている間に話が進んでた。
>>304-305
後者について、generic function model で第一引数を
特別扱いするのがそもそも間違っている気がする。
(……なんか最近似たようなことを書いた記憶があるな)
message passing model に基づいて事象をモデル化したら、
message passing model に基づいた記法で書いたほうが素直になるのは当然でしょう。
そこで後者が文章にするのも大変て言われても、それはそうでしょうな、としか言えない。

無理にオブジェクトを人として扱うなら、
「o 君、p1 と p2 で」じゃなくて、「o1 君と o2 君と o3 君で」と考えた方がいい。
もっとも、それだと三人が一人になったり、
逆に(多値を返すような場合)一人が三人になったりして不気味だけど。

そういう意味じゃ、(例えば)オブジェクトを人としてモデル化したいような場合には
generic function model は確かに向いてないかもしれない。
でも、モデルなんて結局のところ問題把握のための道具でしかないんだから。
通用する範囲で便利に使えればいいし、無理があるような場合には脇に置いといたり、
場合によってはあっさり捨ててしまってもいいんじゃないかな。
どっちのモデルであれ、あるいはそれ以外のどのモデルであっても、固執するのは馬鹿らしいと思う。
ていうか、ひとつの完全なモデルがみつかってなら、
何でこれほどたくさんの「オブジェクト指向」言語が作られているのか、て話になる。

で、lisp のいいところっていうのは、
記法をそこそこ柔軟にモデルに合わせて作り変えられるってとこでしょ?
散々言われてきたことだけど。
例えばあるオブジェクトについて、手続きを順々に追っかけさせる、みたいなことをしたいなら、
自分が上に書いたのや >>311 さんが書いたようなやり方で簡単に出来るわけで、
そうした方が問題をすっきり記述できると判断するなら書きゃいいじゃんてことではあるけれど、
でもそれがどの問題についても妥当であるというなら、それは了見が狭いといいたい。
0314デフォルトの名無しさんNGNG
前置記法がわかりずらいってケチつけてるだけだろ
lisp 族がメジャーになることはないんだから、わざわざ粘着するなよ
0315デフォルトの名無しさんNGNG
連鎖適用って、そんなに嬉しいかな。
何か他の値を返すようなメソッドには使えないけど。
返り値がいらないようなメソッドを続けて使うのって、表示周りとかかな…
0316デフォルトの名無しさんNGNG
連鎖適用って途中で切るオペレータが欲しいんだよな。
NULLやnilのような無効値だったらそれ以上進まないようなやつ。
リスト処理だけなら空リストで済むから問題ないんだけどね。
0317デフォルトの名無しさんNGNG
(macroexpand '(-> obj (f0) (f1 arg1)))
=> (let ((obj1 (f0 obj)))
(if obj1 (let ((obj2 (f1 obj1 arg1))) obj2) obj))

というマクロ->を定義するのは簡単だよね。nilになる一歩手前のオブジェクトを
返してくれる。
0318デフォルトの名無しさんNGNG
(define-syntax chain
  (syntax-rules ()
    ((_ obj n) obj)
    ((_ obj n (m . args) . more)
      (let ((c (m obj . args)))
        (if (eq? c n) n
            (chain c n . more))))))

letの変数ってこれで大丈夫なのかな?
0319デフォルトの名無しさんNGNG
後置記法のLispを作ればいいんじゃないの。
データについて考えてみても、cons してから reverse (nreverse)
ってのをよくやる(見る)けど、あれ無駄な気がしてならない。
0320デフォルトの名無しさんNGNG
>>319
前半と後半の繋がりがよくわからない
0321デフォルトの名無しさんNGNG
>>319
consセルの先頭に突っ込むのとケツに突っ込むコストが同じだというのか。キミは。
0322デフォルトの名無しさんNGNG
dequeが欲しけりゃリストの先頭と末尾を指すconsを一個持てば作れるけどな。
破壊的操作が必要になるのであまり嬉しくないけど、
計算量的にそれが必要ならやればいいだけの話。


0323319NGNG
>>321
いやそういうことではなくて…。後置記法Lispの場合、consで先頭に
突っこんでいくと逆さまになるのも気にならなくなるのでは、
ということです。
0324デフォルトの名無しさんNGNG
そんなあなたにDylanを





いえ、すんません。巣に帰りまつ(;´Д`)
0325デフォルトの名無しさんNGNG
アホすぎ。reverseかけるのは気になるならないの問題じゃないんだが。
0326デフォルトの名無しさんNGNG
(define (copy-list1 l)
(let loop ((l l) (r '()))
(if (null? l) (reverse r)
(loop (cdr l) (cons (car l) r)))))

(define (copy-list2 l)
(let loop ((l l) (c (lambda (x) x)))
(if (null? l) (c l)
(loop (cdr l) (lambda (x) (c (cons (car l) x)))))))

(define (copy-list3 l)
(if (null? l) '() (cons (car l) (copy-list3 (cdr l)))))

(define (copy-list4 l)
(let ((n '(())))
(let loop ((l l) (r n) (end n))
(if (null? l) (cdr r)
(begin (set-cdr! end (cons (car l) '()))
(loop (cdr l) r (cdr end)))))))

速度は
copy-list1 > copy-list4 >>> copy-list2 >>>>>> copy-list3
くらいでした。copy-list4 はなんで遅いんだろ。
0327デフォルトの名無しさんNGNG
>>326
リストの長さや処理系によっても随分違うものになるだろうから
それらを特定しない比較には意味が無いような
0328デフォルトの名無しさんNGNG
copy-list4はrが冗長なパラメータだろう。それはそれとして、
リストの長さを変えても傾向は変わらなかったのか?
0329デフォルトの名無しさんNGNG
(define (copy-list5 l)
(apply list l))
0330デフォルトの名無しさんNGNG
>>328
ほんとですね。とりあえず、

(define (fact f n)
  (if (= n 1) f (lambda (x) ((fact f (- n 1)) (f x)))))

(define (num-list n)
  (let loop ((n n) (r '()))
    (if (zero? n) r (loop (- n 1) (cons n r)))))

として

((fact copy-list1 X) (num-list Y))
みたいな感じで計ってみました。
Yを大きくすると copy-list4が速くなると思ったんですが、
copy-list1の方が速かったです。処理系は Gaucheです。
他の処理系でも試してみます。
0331デフォルトの名無しさんNGNG
cons,cdr,set-cdr!が同じ時間で実行できるとして
copy-list1,copy-list4がそれぞれどれくらいの時間でできるか計算してごらん。

copy-list1はgcの時間をのぞいたら変わらないと思うよ。
■ このスレッドは過去ログ倉庫に格納されています