CommonLisp Scheme Pa ..
[2ch|▼Menu]
263:デフォルトの名無しさん
04/09/10 23:44:32
>>262
Gauche は examples/spigot/ が参考になるかと

264:233
04/09/11 01:41:51
>>263
(2)は define-module, select-module, dynamic-load, provide
の手順でいけるんですね
gauche が理解できる形でstubというのを作ってそこから引っ張るんですね
なんとなくわかったような・・・

@GOSH@ ってのは そのstubというのをつくるコマンドですか?
GOSH getstub $<
スタブとか言葉は聞いたことあるけど実はあんまりわかってないw

265:264
04/09/11 16:06:15
gauche インストールしました
gosh ってgouche のリスナーの名前だったんですね・・・
お恥ずかしい


266:デフォルトの名無しさん
04/09/11 22:18:30
>>258
(process-send-string proc (string-make-unibyte string))
string-make-unibyte してちゃ日本語は無理だよな。
さて、どうするか

267:デフォルトの名無しさん
04/09/12 00:16:38
>>258 266
とりあえず、次ので日本語できたっぽい。
Mac OS X, OpenMCL でだけど
diff -r1.397 slime.el
1430c1430
< (set-buffer-multibyte nil))
---
> (set-buffer-multibyte t))
1439c1439,1440
< (let* ((msg (concat (slime-prin1-to-string sexp) "\n"))
---
> (let* ((msg0 (concat (slime-prin1-to-string sexp) "\n"))
> (msg (encode-coding-string msg0 'euc-jp-unix))
1442c1443
< (process-send-string proc (string-make-unibyte string))))
---
> (process-send-string proc string)))
1502c1503,1504
< (let ((string (buffer-substring start end)))
---
> (let* ((string0 (buffer-substring start end))
> (string (decode-coding-string string0 'euc-jp-unix)))


268:デフォルトの名無しさん
04/09/12 01:00:18
うおおお
sortがでけた

269:デフォルトの名無しさん
04/09/12 16:27:08
Corman Lispの作者のCormanさんから宣伝メールが来たよ。
Lispの処理系売って食ってくというのは苦労してるんかね。
とにもかくにも日本語がちゃんと扱えないことにはねえ。


270:デフォルトの名無しさん
04/09/13 16:15:43
前から思っていたんだけれど、
スペシャルフォームをファーストクラス・オブジェクトにすることはできない
だろうか?
スペシャルフォームを引数にとったり、関数の戻り値としたりできないだろうか?

> or
<#special form>  <-- 通常なら syntax error
> (or #f 3)
3

こんな感じで、スペシャルフォームが単独で入力されても文法エラーに
ならないようにすれば、うまく行くような気がするのだけど、どうでしょう?

271:デフォルトの名無しさん
04/09/13 16:32:46
>>270
Gaucheだとできてしまう。

gosh> set!
#<syntax set!>
gosh> define
#<syntax define>
gosh> (define hoge #f)
hoge
gosh> (set! hoge define)
#<syntax define>
gosh> (hoge x 1)
x
gosh> x
1


272:270
04/09/13 16:37:59
ええー!Gauche って便利なのね。すごーい!

と言うか、なんで PetiteChezScheme だとできないのだろう??
何か不都合があるのでしょうか?
使えるほうが、絶対便利だと思うのだけど。

273:270
04/09/13 16:55:53
すると Gauche では、こんなこともできちゃうのでしょうか?

gosh> ((lambda (x y) (x #f y)) or 3)
3

スペシャルフォームは、car の位置にきたときだけ機能するようにすれば
こういう書き方も ok だと思うのだけど。

274:デフォルトの名無しさん
04/09/13 16:56:18
もはやGaucheは、かつてgccがCじゃなかったくらいにschemeじゃない気がする。
gccの場合はしばらくしたら標準が追い付いてきたので、
schemeもあと十年くらい待てば>>270みたいのが標準で使えるようになるかもよ。


275:デフォルトの名無しさん
04/09/13 17:01:39
>>273
やってみた。

gosh> ((lambda (x y) (x #f y)) or 3)
*** ERROR: invalid application: (#<syntax or> #f 3)
Stack Trace:
_______________________________________
gosh> (let ((hoge or)) hoge)
#<syntax or>
gosh> (let ((hoge or)) (hoge #f 3))
*** ERROR: invalid application: (#<syntax or> #f 3)
Stack Trace:
_______________________________________

意外とよわよわだったな、Gauche……。


276:270
04/09/13 17:17:52
>>275
あれれ、残念。
shiro さん、もし見てたら、ご検討お願いします。

277:デフォルトの名無しさん
04/09/13 17:18:15
guile> ((lambda (x y) (x #f y)) or 3)
3

できました

278:270
04/09/13 17:20:20
>>277
おお!さすが何でもありの Guile!

279:デフォルトの名無しさん
04/09/13 19:01:09
それにしても、こんなに便利そうなのに、どうして標準になっていないのだろう?
何か問題があるのだろうか?

280:デフォルトの名無しさん
04/09/13 19:59:08
そりゃSchemeが便利ならなんでもありとは対極にあるような言語だからだろ


281:デフォルトの名無しさん
04/09/13 20:17:07
マクロの展開についての根深い対立が…。

282:デフォルトの名無しさん
04/09/13 20:32:55
夢の中で問題点を一つ思い付いた。関数はまず全部の引数を評価してしまうが、
syntaxはそうではない。わかりやすいところではand, or, begin, ifなど。

(define foo #f)
(or #t (begin (set! foo 3) foo))
とこれ↓を比べてね:
((lambda (x y) (x #t (begin (set! foo y) y))) or 3)

そう考えるとトップレベルでのみ別の名前に束縛できるというのは
それなりに意味があるかも。
しかしguileだと後者も難なくこなしてしまうようだ。どうなっとるんだ。

guile> (define foo 1)
guile> ((lambda (x y) (x #t (begin (set! foo y) y))) or 3)
#t
guile> foo
1
guile> ((lambda (x y) (x #t (begin (set! foo y) y))) and 3)
3
guile> foo
3

きっと、こんなことやってるからguileは遅いんだな……。


283:デフォルトの名無しさん
04/09/13 20:34:59
>>279
(or a b) はaがtrueならbが評価されないってところが大事なところでしょ。
手続きとして使いたければormapとかanyとかあるわけだし、自分でも作れる
わけだし。
構文は、実行前に意味が確定できることが肝なんであって、>>277みたいのを
標準にする意義がわからん。




284:270
04/09/13 20:45:37
>>282
すばらしい!Guile のその挙動こそ、私が望んでいたものです。

>>283
それが、『Scheme手習い』の「lambdaは最高だ」に、スペシャルフォームを引数に
取れたら非常にシンプルに書けるような例が出ていたのです。
(実際はできないから、本では相互再帰を行って何とか解決していた)

285:270
04/09/13 20:48:12
>>282
Guile の実装はぜんぜん知りませんが、
きっとスペシャルフォームを実行するのは car の位置に来たときだけ、という
ルールでやっているのじゃないかなあ。

そんなに速度も落ちないのじゃないかと思うのだけど。

286:デフォルトの名無しさん
04/09/13 21:36:01
実行時に展開と評価時に展開じゃ速度にかなり違いが出るような気が。

287:デフォルトの名無しさん
04/09/13 21:41:43
"special formを実行する" のは構文を parseするときではないのか?

>>277みたいなのは parseするときに決まってないんだからだめじゃん。

Haskellの世界にでもくれば shortcutなんかわざわざ意識しないでいいよ :-)


288:270
04/09/13 22:02:21
うー、そういう問題があるのですか…。

スペシャルフォームを引数に取れると便利だという例をちょっと
書いてみました。
関数と違い、すべての要素を評価しないスペシャルフォームなので、
途中で結果がわかれば、リストを最後まで評価せずに止まります。

テストはしておりませんので、バグっていたらごめんなさい。

;関数を返す関数。引数に and か or を取る。
(define make-function
 (lambda (s-form)
  (lambda (list0)
   (s-form (atom? (car list0))
       ((make-function s-form) (cdr list0))))))

;リストにアトムが含まれるか?
(define has-atom? (make-function or))

;リストの要素がすべてアトムか?
(define all-atom? (make-function and))


289:270
04/09/13 22:03:35
もしかして、Haskell のように遅延評価がデフォルトだと、
スペシャルフォームのほとんどは不要になるのでしょうか?

290:デフォルトの名無しさん
04/09/13 22:14:28
>>274
標準 (R5RS) では未定義あるいは実装依存とされている領域を利用しているだけだから
scheme ⊃ Gauche だよ

291:デフォルトの名無しさん
04/09/13 23:13:29
ふと気づいたのだけど、マクロもスペシャルフォームの一種だよね?
Guile って、マクロも実行時に展開しているんだろうか?
だとしたら、遅いのも道理だなあ…。

どなたかGuileユーザの方、確かめていただけませんか?

292:デフォルトの名無しさん
04/09/13 23:34:50
guile> (define-syntax my-or
    (syntax-rules ()
     ((_ x y) (or x y))))

guile> ((lambda (s-form y) (s-form #t (display y))) my-or 3)

これを試していただけませんか?
#t が返ってくるなら、マクロを実行時に展開していると思う。


293:デフォルトの名無しさん
04/09/14 00:00:24
>>292
Unbound variable: define-syntax
とか怒られた。

294:デフォルトの名無しさん
04/09/14 00:06:55
あれ?当然エラーは 2つ目の式で出たんですよね?
1つ目のdefine-syntax の式の実行で出たのではないですよね?

するとやはり Guile は他と同じで、パース時にマクロを展開するのかな?

295:293
04/09/14 00:14:21
>>294
ごめん。(use-syntax (ice-9 syncase))忘れてた。
2つめの式で
ERROR: invalid syntax my-or
って出た。

296:デフォルトの名無しさん
04/09/14 01:24:16
了解。いずれにせよ、マクロ展開は実行時ではなく、解釈時なのね。
どうもありがとう。

そうしてみると、first class objectとして扱える special form はGuile の
場合、システム組み込みのものだけなのか。
ユーザ定義のマクロと、システム組み込みの special form を区別せずに扱えるのが
Lisp の良さの一つなのに、これでは価値半減だなあ。
実行してみるまで区別がつかないから、わかりにくいバグの元にもなりそうだ。

これなら、special form に別名を付けることしかできない Gauche の方が現実的な
落としどころのような気がする。

special form を first class として扱うためには、マクロ展開を実行時に行っても
構わないような、マシンパワーのあまりある時代を待つしかないのかもしれない。

297:デフォルトの名無しさん
04/09/14 01:28:42
まてよ。Gauche でも、マクロには別名は付けられないよね?
(define new-or my-or) は syntax error になると思う。

すると、ChezScheme のように、special form を一切拡張しないのが一番
現実的なのだろうか。何か寂しいなあ。

298:デフォルトの名無しさん
04/09/14 01:39:04
Gaucheではできる。Gaucheでは、コンパイル時に(手続き呼び出しではなく)
マクロだとわかるものならマクロ展開をしてくれるし、マクロの名前は
マクロそのものを返す。(define new-or my-or)も可能。

syntax classをapplicable objectにして、実行時に展開したら
おもしろいかも。evalが必要になるし、トップレベル以外の環境は
取得できないから無理だろうけどさ。

299:デフォルトの名無しさん
04/09/14 05:00:28
>>270
そういうのはマクロでやる。
実際、make-functionのコンパイル時にはs-formが構文かどうかは
わからないわけだから、コンパイラは ((make-function s-form) (cdr list0))
を評価してからs-formを呼ぶってコードを出すしかないじゃん。

>>287
Lazyなセマンティクスなら評価順の問題は出ないけど、「構文を
パラメタライズする」っていうのはもっと広い問題を含んでる。
Haskellでも、構文要素である '\' や '=' を関数引数として
渡すわけにはいかない。
構文のパラメタライズってのはメタプログラミングしてることになる。
Lispではマクロがメタプログラミングの道具。



300:270
04/09/14 10:38:48
>>298
やっぱり Gauche はバランスがよく取れているということなのでしょうか。


>>299
そうか!マクロか!と思って、さっそく>>288 のコードをマクロ化してみました。

;元の関数
;(案の定バグがあった(停止しない)ので修正してある。)
(define make-function
 (lambda (s-form null-value)
  (lambda (list0)
   (if (null? list0)
     null-value
     (s-form (atom? (car list0)
         ((make-function s-form null-value) (cdr list0))))))))

;マクロ化したもの
(define-syntax make-function
 (syntax-rules ()
  ((_ s-form null-value)
   (lambda (list0)
    (if (null? list0)
      null-value
      (s-form (atom? (car list0))
          ((make-function s-form null-value) (cdr list0))))))))

そうしたら、マクロ展開が停止しないんです。再帰的定義なのに停止条件がないから。
この場合、どう書いたらよいのでしょうか?ヘタレですみません。

301:270
04/09/14 13:12:00
『On Lisp』邦訳 10 マクロのその他の落し穴 10.4 再帰(P81)を読んでみました。
思ったより、解決は難しそうです…。

302:デフォルトの名無しさん
04/09/14 15:30:55
>>300
> やっぱり Gauche はバランスがよく取れているということなのでしょうか。

つーより、事前にコンパイルするんじゃguileみたいな挙動は不可能じゃね?
S式をそのまま解釈実行するのでないと。当然その場合実行速度は遅くなる。


303:デフォルトの名無しさん
04/09/14 15:58:30
なんか似たような話を見たことあるなあ……と思ってたんですが、
これなんか参考になりませんか? Common Lisp だけど。

URLリンク(home.comcast.net)

304:デフォルトの名無しさん
04/09/14 16:14:46
>>270
実行時の停止条件と展開時の停止条件をごっちゃにしてると思われ。
停止を実行時に判断するなら、ループは実行時手続き呼び出しになる。

(define-syntax make-function
(syntax-rules ()
((_ s-form null-value)
(rec (f list0)
(if (null? list0)
null-value
(s-form (atom? (car list0))
(f (cdr list0))))))))

recはsrfi-31ね。letrecを使ってもよい。

停止を展開時に判断する場合は、実行しないでも停止条件がわかる
ことが必須。たとえば引数がリテラルリストで与えられているとか。
その場合はsyntax-rulesで再帰を書けばいい。

(syntax-rules ()
((_ s-form null-value val0)
(s-form (atom? val0) null-value))
((_ s-form null-value val0 val1 val2 ...)
(s-form (atom? val0)
(make-function null-value val1 val2 ...))))







305:270
04/09/14 22:43:09
ありがとうございました。言われてみれば『On Lisp』そのままの話でしたが、
具体的に書いていただくまで分かりませんでした。お恥ずかしい。

rec という構文は初めて知りました。
ChezScheme ではそのままでは動かなかったので、少し変えました。

;; rec 版
(define-syntax make-function
 (syntax-rules ()
  ((_ s-form null-value)
   (rec f
    (lambda (list0)
     (if (null? list0)
       null-value
       (s-form (atom? (car list0))
        (f (cdr list0)))))))))

;; 名前つきlet (letrec)版
(define-syntax make-function
 (syntax-rules ()
  ((_ s-form null-value)
   (lambda (list0)
    (let loop ((list0 list0))
     (if (null? list0)
       null-value
       (s-form (atom? (car list0))
        (loop (cdr list0)))))))))

(define has-atom? (make-function or #f))

(define all-atom? (make-function and #t))

306:270
04/09/14 23:26:58
今回は本当に勉強になりました。
今まで、special form が first class でない理由がずっとわからなかったの
ですが、答えはこうだったのですね。「マクロがあるから」

first class というのは関数抽象に関する概念で、special form は構文であるから、
そこには収まらない。それを扱うのは構文抽象の手段であるマクロ。

漠然としていますが、こういう理解でよろしいでしょうか。

以前 ruby の matz 氏が、マクロでできることはほとんど高階関数でできてしまう
と言っていましたが、決してそうではないですね。

今までマクロと言うと、パワフルだが汚いという負のイメージが強かったのですが、
今回それが変わりました。むしろ、関数抽象と補い合って Lisp の総体を支える
本質的なものだと感じました。今後もっとマクロを深く知りたいです。

ありがとうございました。

307:デフォルトの名無しさん
04/09/15 01:29:34
高尚なネタで盛り上がってるとろこスマン。
BKNL,TBNL,IMHO,UncommonWeb,AllegroServe+WebActions,CL-HTTPといろいろある
ウェブサーバ on CLなモノタチのなかでこのスレ住民のお勧めはどれなのか教えて欲しい。
できれば理由も。処理系はACLかCMUCLの予定です。

308:デフォルトの名無しさん
04/09/15 10:05:40
>>307
おれも知りたいな
ACL の WebAction はセミナー聞いただけだと
そう良くも悪くもなさげだった、ほとんど Apache Struts の焼直しって感じだけど
他のも Web 「アプリケーション」サーバーなのかしら?



309:デフォルトの名無しさん
04/09/16 00:57:02
スレの内容が高度すぎる…
初心者スレは良かった…

310:デフォルトの名無しさん
04/09/16 04:28:41
ちっとも高度じゃないよ。
分からないうちは飛ばしとけ。

311:デフォルトの名無しさん
04/09/16 10:42:55
>>309
大丈夫。あきらめなければそのうち、ちゃんとわかるようになるから。
シンプルなのが Lisp の身上。
スレの過去ログの、昔読んで分からなかったところが、少したつととても面白く
読めるようになります。経験者は語る。

-------------------
新山氏の日記に、久しぶりに Lisp のことが書かれている。
URLリンク(tabesugi.net)

新山氏は相変わらず冴えてます。読んで「うわー、そういう感じ、よく分かる」
と思った人も多いのではないだろうか。

312:デフォルトの名無しさん
04/09/16 13:59:44
>>306
> マクロでできることはほとんど高階関数でできてしまう

そこで高階関数と言っているのは、評価したくないコードブロックをラムダで
括ってしまうということを言ってるわけで、>>300 の前半の関数版に対して

;リストにアトムが含まれるか?
(define has-atom? (make-function (lambda (a b) (or a b)) #f))

と書けばよい、ということじゃない?


313:デフォルトの名無しさん
04/09/16 15:44:06
>>311
>「うわー、そういう感じ、よく分かる」
Lisp側から見て? それともPython側から?
ちなみに俺はSchemeもPythonも好きで両方使ってるけど,
Lisp側の意見はあまり共感できないなぁ.(マクロまんせーには同意するけど)

314:311
04/09/16 15:56:34
>>312
確かに引数として与えたとき or は評価されないけれど、has-atom? の内部で
or ではなく、or に似た働きの関数になっちゃうでしょ? or に与えたい引数
の両方をまず評価してしまうから、リストを最後まで評価しないと止まらない。

>>313
Python 側。と言うか、外から見た Lisper の雰囲気。(私は Python 知らないので)

315:312
04/09/16 16:42:23
>>314
あーそうか

(define make-function
  (lambda (operator null-value)
  (lambda (list0)
  (if (null? list0)
  null-value
  (operator (lambda () (not (pair? (car list0))))
  (lambda () ((make-function operator null-value) (cdr list0))))))))

(define has-atom? (make-function (lambda (a b) (or (a) (b))) #f))

こんな感じでどう?もしかしてまた勘違いしてるかな


316:デフォルトの名無しさん
04/09/16 18:15:12
>>315
今度はOK。つうか、煩雑で最初はよく分からんかった。
分かりやすいよう、遅延評価に直せるところを書き直してみた。
(かえって分かりづらい?)
やっぱりマクロのほうが分かりやすいと思う。

;;遅延評価版
(define make-function
 (lambda (operator null-value)
  (lambda (list0)
   (if (null? list0)
     null-value
     (operator (delay (atom? (car list0)))
          (delay ((make-function operator null-value) (cdr list0))))))))

(define has-atom? (make-function (lambda (a b) (or (force a) (force b))) #f))


それにしても、関数型言語方面の人が「Lispで遅延評価など書いておれるか!」と言ってるけど
気持ちがわかったような気がする。やっぱり煩雑だよね、これ。

317:デフォルトの名無しさん
04/09/16 19:14:58
リストの評価が途中で止まるのは、いずれもspecial form である or のおかげ
なのだから、or をそのまま渡せるマクロのほうが、はるかに自然。

or に仕事をさせるために、lambda や delay で囲んで、引数の強制的な評価を
回避させなければならない高階関数は冗長。

318:デフォルトの名無しさん
04/09/16 19:23:34
細かい話だけど、それぞれ1個目の delay と force 、要らないじゃん。

319:デフォルトの名無しさん
04/09/16 22:43:03
special-formをfirst-classにするってことは,
実行時にマクロ展開を行わせることになるよね.
そうすると静的スコープがグチャグチャになるような,ならないような….
あぁ,メタメタしてワケ分からん.

ところで,暗黙のforceを実装した処理系ってある?
暗黙のforceを実装してれば,遅延評価版>>316とかは,delay一つでよくなる.

320:312
04/09/17 00:45:57
>>318
そうだね、 or の第一引数はかならず評価されることが決まってるから
delay する必要はないのか

>>316-317
冗長で分かりにくい、こんなコード書きたくも読みたくもない、というのはもちろん同意。
今回意地になってしまったのは >>306

> 以前 ruby の matz 氏が、マクロでできることはほとんど高階関数でできてしまう
> と言っていましたが、決してそうではないですね。

に反論したくなっただけdeth。テヘ


321:デフォルトの名無しさん
04/09/17 09:16:08
>>320
> 以前 ruby の matz 氏が、マクロでできることはほとんど高階関数でできてしまう
> と言っていましたが、決してそうではないですね。

これ,orとかの評価を遅延させるためのマクロのことを念頭に置いてるんですかね.
「できる」と「やりやすい」は違うし,だいたい,できないこともおおいじゃん...

322:デフォルトの名無しさん
04/09/17 11:56:01
やりやすくないとやりたくない.

323:デフォルトの名無しさん
04/09/17 13:39:34
>>321
マクロでしかできないことってどういうものがありますか?
マクロは興味はあってもとっつきにくいなあと思っています。
教えてもらえるとイメージが湧くかも。


324:321
04/09/17 13:57:18
URLリンク(www.shiro.dreamhost.com)
マクロの応用方法を分類して解説しているので,参考になるのでは.

「宣言的コードにみせる」や「ミニ言語のうめこみ」あたりが
美しいマクロの使い方だとおもいます.

325:デフォルトの名無しさん
04/09/17 14:19:47
>>321
まさに去年の今頃、似たような話をしていた記憶が。懐かしい。
ちなみに matz 氏の発言ていうのはこの辺。
URLリンク(www.rubyist.net)

何となくだけど、matz 氏の意図しているところは
「dolist って for-each でいいじゃん?」ていう程度の話な気がする。
遅延評価がどうとか call-by-name がどうとかってところまでは風呂敷は広げてない感じ。

326:321
04/09/17 14:38:04
ああ,これって算符の記でやってた議論なんですね.しらなかった(赤面)
両者のスタンスの違いがよくわかりますた.


327:デフォルトの名無しさん
04/09/17 22:04:43
評価を遅延させるだけの目的でマクロを使うのはよくないと思う.
引数が評価されるかどうかが定義を見ないと判らないわけで,
むしろ可読性を損なっている気がする.
マクロはマクロを使わないとできないこと,例えばdefineを拡張して
パターンマッチできるようにするとか,そういう目的で使うべき.

328:デフォルトの名無しさん
04/09/17 23:35:35
Common Lisp使ってCみたくメモリ上のビット単位まで意識したコードって簡単に
書けますか? 書けるとしたらその方法が知りたいです。memory mapped I/Oの操作
みたいな低レベルな操作ができるのかな、ってのと、やっぱりそんな処理はCでヤレ、
そもそもLisp使ってやる内容じゃないだろ、って結論しかないのかを教えてくれるとうれしい。

329:デフォルトの名無しさん
04/09/18 01:26:48
素人でスマンが、Cで簡単に拡張ライブラリが書けるような
Lisp処理系を使う、って答えになるんじゃなかろうか。

330:デフォルトの名無しさん
04/09/18 01:33:48
最近の主なLisp処理系ならFFIでCのコードを呼べて楽よ。
>>328みたいなこともやればできそう。
でも分野的に、Cで書く方が直感的でメンテもしやすい気がしなくもないので、
そういうコードをCで書いてFFIで使うというのがいいんじゃないかい。




331:328
04/09/18 02:36:20
レスどうもです。やっぱりFFI使ってCで書くのが定石なんですね。
Cltl2眺めててbit-vectorのオブジェクトの存在するアドレスを物理メモリにマップできれば
もしかして・・・と思ったのですが違ったようです。LispMachineとかだとできたのかなぁ。
データの圧縮とかビットマップインデックスみたいに素のLispが提供していないメモリ上のデータ構造を
ゴリゴリ扱いたいなぁ、と思ったらLisperの取る道はFFIしかないんですかね。それともマクロで
抽象化してarray :element-type (unsigned-byte 32)の上で操作するのでしょうか。

332:デフォルトの名無しさん
04/09/18 03:06:04
物理メモリにmapするには、もひとつOSの助けも必要だと思われ。
Linuxはユーザ空間にmemory mapped I/Oをmapできたんだっけか。
ユーザ空間にI/OをmapするAPIと、具体的な仮想アドレスのreferenceを
取得できるAPIをFFIで書いたらできるのかな。


333:デフォルトの名無しさん
04/09/18 03:26:40
結局そういうインタフェース作ったとして問題は参照方法だろ
さすがにメモリ走査とかはポインタないと辛い
Cでやった方が全然楽だし速いよ

(let (ptr (make-integer-ptr mem)) ;; ポインタの作成
(ref ptr) ;; 参照
(deref ptr value) ;; 逆参照
(inc ptr)

こんなことやってられっか?
実際は型の問題もあるし、もっと煩雑になる
そもそも演算子がないのが痛い

int *ptr = mem; // ポインタの作成
&ptr; // 参照
*ptr = value; // 逆参照
++ptr;

やっぱ記述量が割に合わない

334:デフォルトの名無しさん
04/09/18 03:35:32
餅は餅屋

335:328
04/09/18 03:55:28
はぅあ。袋叩きにあってしまいましたな。記述量が割に合わないとかLisp向きじゃないよなぁ
とは思いながらも知らない世界があるかも程度の好奇心で聞いただけなのでした。

>>334 餅は餅屋
御意。いまも仕事でLispのコード書いてたんだけど、Lispで書いてるととにかく楽なんで
何でもかんでもLispで書けないかなとか思った私が阿呆でした。
どうでもいいけど、みんなこんな時間まで何やってんの?皆もデスマ?

336:デフォルトの名無しさん
04/09/18 04:01:40
Schemeで名前空間で名前を分類するようなことをしたいのですが、どういう方法を
取ればよいのでしょうか?
C++でnamespaceでモジュール全体を囲って名前の衝突が起きないようにして、
using namespaceで名前空間を使うというようなことです。
名前空間を階層化したりもしたいのです。


337:デフォルトの名無しさん
04/09/18 04:22:51
標準的な方法はないから
toplevelをletか何かで包んで必要な名前だけ外部に出すとか

(define proc1 #f)

(let ()
(define (proc1-sub1) ... )
(define (proc1-sub2) ... )
(set! proc1 proc1-sub1)) ;; export

あとは処理系依存だから、付属のマニュアルでも嫁

338:デフォルトの名無しさん
04/09/18 05:32:43
>>328
>>338 の言う通り、やってできなくはないと思う。mapしたアドレス値を
取得するのと、そのアドレスにアクセスするプリミティブは処理系
依存になるが。だがCでポインタを扱いなれてると、Lispでのアクセスは
冗長だね。マクロが使えることはメリットだけど。



339:デフォルトの名無しさん
04/09/18 09:28:32
>>336
処理系依存でよければmoduleシステムやなんやらを使うのがいいでしょう。

どうしてもportableでやりたいなら、top levelの束縛を変更する関数を
マクロで置き換えて、ほげほげとか。
って、top levelの束縛をマクロにするのはR5RS的にはだめなんだっけか...

340:デフォルトの名無しさん
04/09/18 10:40:21
スペースで区切られたテキストが以下のようにあったとして
A B C
D E F
↓(変換)
A
D

B
E

C
F

みたいな文章に整形するプログラムを作ろうと思ったのですが
いまいちエレガントにかけません
読み込むテキストファイルを"test.dat"として
以下のように書きました

(with-open-file (in "test.dat" :direction :input)
(let ((buff)
(str1)
(str2)
(str3)
(vstr))
(while (setq buff (read-line in nil))
(setq vstr (split-string buff "\t"))
(setq str1 (concatenate 'string str1 (first vstr) "\n"))
(setq str2 (concatenate 'string str2 (second vstr) "\n"))
(setq str3 (concatenate 'string str3 (third vstr) "\n")))
(format t "~A\n~A\n~A\n" str1 str2 str3)))

誰かアドバイスください・・・

341:デフォルトの名無しさん
04/09/18 13:02:49
縦読みデコーダでも作るの?


342:340
04/09/18 13:15:05
>>341
そんな大層なものではなくて
練習用に書いているのですが・・・

上の例では3列と固定しているところを可変で
対応できるようにしたいのです
str1,str2,str3 とかやるのは格好悪いし・・
もっとすっきり書けませんかね?

343:デフォルトの名無しさん
04/09/18 13:32:22
下のコードはヒントにならない?
(mapcar #'list '(a b c d e) '(3 4 5 6 7))
=> ((a 3) (b 4) (c 5) (d 6) (e 7))



344:340
04/09/18 15:24:32
>>342
有難うございます
で、さっそく以下のように書いてみたのですが、
結果が nil になってしまいます

(defun util (fname)
(with-open-file (in fname :direction :input)
(let ((buff)
(output))
(while (setq buff (read-line in nil))
(setq output
(mapcar #'list output (split-string buff "\t"))))
(mapcar #'(lambda (s) (format t "~A\n" s)) output))))

(util "test.dat")
nil

なぜ nil になってしまうのでしょうか?

345:デフォルトの名無しさん
04/09/18 16:18:32
whileの返り値

346:デフォルトの名無しさん
04/09/18 18:07:39
(defmacro for ((var start stop) &body body)
 (let ((gstop (gensym)))
  `(do ((,var ,start (1+ ,var))
     (,gstop ,stop))
     ((> ,var ,gstop))
   ,@body)))

これはOnLispに載っている "正しいforマクロ" (図42)
ですが、このgensymの例が何故正しいのかよくわかりません。

bodyの中にフリーなgstopが出てきたらやはり名前衝突を
起こしてしまう気がするのですが、私は何か勘違いして
いるのでしょうか。

347:デフォルトの名無しさん
04/09/18 18:16:40
>>344
(mapcar #'list nil '(1 2 3)) => nil だよ
まず output として '((A B C) (D E F)) を作ってこれを '((A D) (B E) (C F)) に変換する
と思えば良いんじゃない?
あんま考えてないけど↓
(defun util2 (output result)
(if (car output)
(util2 (mapcar #'cdr output) (cons (mapcar #'car output) result))
(reverse result)))

>(util2 '((A B C) (D E F)) '())=>((A D) (B E) (C F))


348:デフォルトの名無しさん
04/09/18 18:45:50
gensymはinternされない (システム内部の、名前からシンボルへの
対応表に登録されない) シンボルを作るので、このマクロの展開時に
作られるシンボル (#:G0031とか) と同じシンボルを外から与えることは
できない。(同じ名前にしてもシンボル自身は別オブジェクトなので
衝突しない)



349:340
04/09/18 18:56:21
nil にリスト追加してもnilなんすね
また修正してみました
途中経過ですが・・・
(with-open-file (in "test.dat" :direction :input)
(let((buff)
(output '()))
(while (setq buff (read-line in nil))
(if (null output)
(setq output (split-string buff "\t"))
(setq output
(mapcar #'list
output
(split-string buff "\t")))))
output))

としたら2行だと上手くいきますが => ((A D) (B E) (C F))
3行目からは(((A D) G) ((B E) H) ((C F) I))
となってしまふ・・・
<<347 のように今度は再帰で考えて見ます

350:デフォルトの名無しさん
04/09/18 19:24:40
>>348
ああそうか!
` が付いて無いからマクロの展開時に (let) は消えるんですね
納得・・・ありがとうございました

351:340
04/09/18 19:48:28
ようやく上手くいきました
良いLISPの勉強になりました

(defun util (filename)
(with-open-file (in filename :direction :input)
(let
((buff)
(output))
(while (setq buff (read-line in nil))
(if (null output)
(setq output (split-string buff "\t"))
(setq output
(mapcar #'(lambda (v1 v2)
(if (listp v1)
(append v1 (list v2))
(list v1 v2)))
output
(split-string buff "\t")))))
output)))

知恵を下さった皆さん有難うございました
もっとエレガントにいけるとかあったら
ぜひ教えてください

352:ミミ
04/09/19 10:40:16
Scheme の継続と、Win32 API のウィンドウ プロシージャ コールバック
って、共存可能だと思いますか?

353:デフォルトの名無しさん
04/09/19 11:07:15
不可能な理由がなかったら可能だよ。

354:& ◆TACpYgPjX6
04/09/19 11:17:07
それがよくわからないんですよ。
だって、OS 側でどんな処理をしているか分からないじゃないですか。

たとえば WM_KEYDOWN ハンドラ内で継続を作成して、
一度そのハンドラを終了して OS に制御を返すでしょ。
そのあと WM_LBUTTONDOWN ハンドラ内で
先ほどの継続を呼び出すと、WM_KEYDOWN メッセージの処理が
再開されるわけですよね。

OS 側でスタック上のデータではない
グローバル変数をいじっていたとすると、
コンテキストがめちゃくちゃになって、
よくない気がするんです。

355:デフォルトの名無しさん
04/09/19 11:26:55
> OS 側でどんな処理をしているか分からない

分からない以上、可能だという確認ができないんじゃないか?

356:ミミ
04/09/19 11:31:53
いえいえ、今の私の知識ではわからないということなんです。
どなたか深い知識をご存知の方はいらっしゃらないかなと思いまして。

357:デフォルトの名無しさん
04/09/19 11:33:02
354の話で使いたい場面と、問題意識が少しわかったので
もう少し整理してから、その問題意識を中心に調べものしたらわかるのではないかな。
イベントハンドラまわりなんだよね。
;;; Windowsのことはよく知らないけど...


358:& ◆TACpYgPjX6
04/09/19 11:36:15
実は Windows 専用 Scheme を作りたいと思っているんです。
特にシステム ハックをするためのツールを
Scheme でガンガン作りたいんですよねぇ。

コンセプトは
"Scheme as a better C."
"Scheme as a hacking tool."

359:デフォルトの名無しさん
04/09/19 11:50:34
で?

360:ミミ
04/09/19 11:51:32
協力してくれたらうれしい。
できたら使わせてあげるから。

361:デフォルトの名無しさん
04/09/19 11:54:40
面白そうではあるが,コールバックまで正常動作させようとすると
継続はおろかクロージャさえ厳しいだろうな…

362:& ◆TACpYgPjX6
04/09/19 11:56:17
だいたいですね、Lisp 系の言語って、
どれもこれも Unix っぽいのがよくないと思うんですよ。
Perl や Python も同じなんですけど、
Java はちょっと違う感じ。

Windows みたいな素敵なシステムに、
Scheme みたいな素敵な言語があれば、
みんな幸せだろうなぁ、と思ってさ。

363:ミミ
04/09/19 11:59:09
すいません、どうしてクロージャが難しいのでしょうか。
何も OS が直接クロージャを呼び出すことは期待していないです。
間に C 関数をかませば問題ないですよね?

> 面白そうではあるが,
ありがとう。

364:デフォルトの名無しさん
04/09/19 12:00:52
PythonはMac出身じゃなかったっけ.
まぁ、それはともかく、Unixっぽいってどういうこと?

365:デフォルトの名無しさん
04/09/19 12:13:05
>>363
話の流れからすると,Win32APIを丸々wrapするんじゃなくて,
Cの関数を直接呼び出したりできる機構を用意しようってことだよね?

366:& ◆TACpYgPjX6
04/09/19 12:18:32
一番大きなのは、コンソール (標準入出力) を前提としていること。

あと、いろんな Scheme 処理系をみてみても、
最初にサポートされるライブラリが POSIX ライブラリを移植したものとか、
GNU の readline たら curses たら、
/etc/network の存在を仮定したソケット ライブラリとか (Winsock にしてくれ)、
Windows で使うにはほとんどいらないものばっかりあって、
肝心の Windows 用のライブラリがないんですよ。

レジストリ アクセスや COM バインディングは必須でしょう。
もちろん ウィンドウ プログラミングができないとだめ。
(Unix では X がオプションだから困る)

あと、リソースのアクセスとか、シェル サービスへのアクセスとか、
さまざまな Win32 API をオブジェクト指向的にパックしたものとか
Win32 のセキュリティ機構は Unix と大きく異なっているから、
それを無理やり Unix 的に狭めても、使う気になれない。

Scheme だけで DLL を書くとか、サービス書くとか、
スクリーン セーバー書くとか、Scheme だけでデバドラ書くとか。
そんなのができない。

しようとすると、既存の Scheme に拡張機能を実装しないとだめで、
その Scheme 実装系の内部動作から把握しないとだめってことになる。
しかも Scheme 実装系自体が Unix を基盤としているので、
Windows 用に最適化されているわけでもない。

であれば、Windows 専用の Scheme 実装の上に
Windows 専用のライブラリを構築するほうが
ずっといいと思う。

367:デフォルトの名無しさん
04/09/19 12:27:13
うーん、Scheme.NETか?

368:ミミ
04/09/19 12:28:34
>>365
> 話の流れからすると,Win32APIを丸々wrapするんじゃなくて,
> Cの関数を直接呼び出したりできる機構を用意しようってことだよね?

構想としては WIn32 API (というか任意の DLL 関数)
をすべて生で呼び出し可能にしたいとは
思っています (間に多少のサンクは入ってもよし)。

VB の Declare 文みたいに、Scheme ソース上で
宣言するだけで、外部の API を呼び出したいです。

たとえば、
(dll-import MessageBox
((DWORD hwnd)
(WSTR text)
(WSTR caption)
(UINT type))
(alias "MessageBoxW"
stdcall)
)
という感じで宣言して、
呼び出すときは
(MessageBox 'hwnd hwnd
'text "テキスト"
'caption "キャプション"
'type (| MB_OK MB_ICONINFORMATION) )

コールバックの話は、ウィンドウを使いたいために出てきた話です。
ウィンドウを使うには OS からのコールバックとして実装しなくてはならず、
その場合、継続と相性悪くないのかなぁ、とふと思ったのです。

369:デフォルトの名無しさん
04/09/19 12:34:50
>>366
> であれば、Windows 専用の Scheme 実装の上に
> Windows 専用のライブラリを構築するほうが
> ずっといいと思う。
そういうことは、既存Scheme処理系をWindowsに移植しようとして
挫折してからいうべきなのではないか。先人の知恵は偉大だよ。
;;; 挫折というのは移植者の能力不足のことではないよ。

あ、もしかして、scheracy?

370:& ◆TACpYgPjX6
04/09/19 12:37:25
>>369
>あ、もしかして、scheracy?
え? Scheme ヤラシイ?
なんですかそれは。

371:デフォルトの名無しさん
04/09/19 12:40:07
>>367
だよね。他にもあるかも知れないけど、
.NETFramework をサポートする Scheme を開発するプロジェクト

URLリンク(radio.weblogs.com)
URLリンク(www.cs.indiana.edu)

372:デフォルトの名無しさん
04/09/19 12:45:12
チョット前に出てたハンディスキームじゃダメなのか?

373:ミミ
04/09/19 12:49:18
>>371
情報ありがとうございます。一度よく調べてみます。

うーん、私は .NET 勉強してからしばらくたつので、
いろいろ忘れていますが、.NET ってそんなにいいものですかね?

どうも GUI が重ったるいし、C# も VB.Net もなんかシンプルじゃないし、
.NET ライブラリってあんまり洗練されていないような気がするし (MS的ゴテゴテ)、
いじってたらバグがごろごろ出てきたし (もう直ってるだろうけど)
"as a hacking tool" というコンセプトと馴染むでしょうか。

"as a hacking tool" ===> "cool and cute" ですよ?


374:& ◆TACpYgPjX6
04/09/19 12:55:32
>>372
> チョット前に出てたハンディスキームじゃダメなのか?
むむ!
これ、なんだかよさげですね。
こんなのがあったんですね。
ちょっと今日の宿題にしてみます。
ありがとうございます!

375:デフォルトの名無しさん
04/09/19 13:13:42
おぇ

376:デフォルトの名無しさん
04/09/19 13:17:42
"as a hacking tool"
===> "as a hacking tool"

377:デフォルトの名無しさん
04/09/19 14:24:34
なんでハンドル二つ使って常時ageなんだ?

378:デフォルトの名無しさん
04/09/19 14:34:01
Cからのscheme呼出しの中で補足された継続のエクステントが無制限な処理系ってあるの?
GaucheでもCからのコールバックで補足されたもののエクステントはコールバック内に限定されるし

379:デフォルトの名無しさん
04/09/19 15:02:33
>>363
クロージャが難しいというよりはガーベジコレクションが難しそう.
Schemeで書かれた関数をWin32APIに渡して,コールバック関数として登録したとして,
その関数がいつまで使われるかはSchemeインタプリタ側では判別できないと思う.

380:デフォルトの名無しさん
04/09/19 16:06:22
>>377
1. 2ch が Netscape や Mozilla に対応していない。
2. よって、cookie に書き込まれた全角のハンドル名が化ける。
3. あわててハンドル名を入れなおすと、そのときは正しい名前で掲示板に
  書き込まれる。
4. 次に書き込むと、またハンドルが化ける。
5. 以下繰り返し。

Netscape, Mozilla ではハンドルは半角英数にするのが吉。

常時 age については分からない。

381:デフォルトの名無しさん
04/09/19 16:13:53
>>380
> >>377
> 常時 age については分からない。
sage を知らない、だろうな。

382:デフォルトの名無しさん
04/09/19 17:31:16
> Windows みたいな素敵なシステムに、
ここんとこに賛同できないのは漏れだけなのか。s/Windows/MacOSX/だったら同意なんだが。

383:デフォルトの名無しさん
04/09/19 17:42:53
その部分は罠と判断した。

384:デフォルトの名無しさん
04/09/19 17:53:10
>>366
> 一番大きなのは、コンソール (標準入出力) を前提としていること。

なにか大きな誤解をしているような。
Schemeって必ずしもトップレベル環境のreader/writerと標準入出力が結びついている
必要はないでしょ。Dr.Schemeとか触ってみれば? URLリンク(www.drscheme.org)

あとDLLの動的呼び出しそのものはそれほど難しくないと思われ

URLリンク(www.kt.rim.or.jp)
> 共有オブジェクト(Win32ではDLL)を動的にロードし、
> 中の関数をscheme コードから呼び出すことができる。
> さらにコールバック関数をscheme コードで記述できる。


385:デフォルトの名無しさん
04/09/19 22:06:34
DrSchemeって、一応他のエディタで編集してロードすれば、日本語表示できるみたいだな。
例えば、「あ」と言う文字のように二文字目が\と同じコードの場合には「あ\」と、\を余分にくっつけて
\\を\と認識させるという技を使わなくちゃいけないのが面倒だけど。

ランタイムDLLが必要になるがEXEも作れるようだし、俺の中ではDrScheme最強になりつつある。

386:デフォルトの名無しさん
04/09/20 01:04:59
gaucheでhtml解析するときって皆さんどうやってます?
saaxとかつかってます?
それとも自分で解析モジュールを書いちゃいます?

387:デフォルトの名無しさん
04/09/23 02:10:26
やっと cygwin + slib のインスコ完了したよ・・・
なんでこんなに疲れるんだろう

388:デフォルトの名無しさん
04/09/23 11:27:01
>>386 これは? 使ったことないけど。
URLリンク(www.neilvandyke.org)


389:デフォルトの名無しさん
04/09/23 18:33:55
gosh のload-path は add-load-path 以外に方法がないのですか?
毎回指定するの面度印ですけど・・・

390:デフォルトの名無しさん
04/09/23 18:40:08
>>389
command line optionの-I

391:デフォルトの名無しさん
04/09/23 19:04:22
>>368
継続はコールバックに跨らなければ問題ない。
ハンドラからtoplevelに直接行ったりきたりする様な継続の呼び出しは
不可能ではないけど、コールバックを叩くWindows側で何をしているのかわからんから、
こっちはやらない方が良いとは思う。
ちゃんとコールバックに制御を返却する当てがあるなら、たぶん問題なし。
これに関しては結局セオリーみたいのは見つからなかった。

(deine user32 (loadlib "user32.dll" ))
(define DefWindowProc (getproc user32 "DefWindowProcA" __stdcall '(h m w l)))

(define handler (make-callback __stdcall
(lambda (hwnd msg wparam lparam) (DefWindowProc hwnd msg wparam lparam))))
(define (single-window handler) (make-window handler))

自作の処理系ではこういう感じで窓を作成する。
make-callbackでクロージャとC関数をブリッジする以外に特別な物はない。
schemeの様に内部定義を許す言語のメリットはここから。
handlerはclosureそのものなので、関数外の局所変数をあえて引数渡しする必要がなく、
C言語だとグローバル変数に移したり関数で分離していた箇所を一つにまとめることができる。

(define (test foo)
(make-window (make-callback __stdcall (lambda (hwnd msg wparam lparam)
(display foo) ;; ハンドラ外の変数の参照
(DefWindowProc hwnd msg wparam lparam))

この辺の自由度はC言語と比べると比較にならない。(gccはExtensionで関数内関数が
使えるんだけど制限が多く、schemeの様に内関数同士の再帰やコールバック関数にできない。)

ただね、いまんとここれ使って何がしたいって訳でもないので、そのまま放置状態。
とにかく機構そのものより、ラッパとか書くのが面倒すぎて、型変換も適当。

392:& ◆TACpYgPjX6
04/09/23 19:48:16
>>391
> 継続はコールバックに跨らなければ問題ない。
> ちゃんとコールバックに制御を返却する当てがあるなら、たぶん問題なし。
> これに関しては結局セオリーみたいのは見つからなかった。

OS から コールバック A が呼ばれ、そこで継続 ContA を作成して、
トップレベルに束縛したとします。
次に、OS から別のコールバック B が呼ばれ、そこから ContA を呼び出すとします。
ContA を呼び出した直後は別に問題は発生しませんよね。
問題は、ContA を呼び出し後に、コールバック A から呼び出し側に戻って
しまうことが問題なのですよね。

であれば、コールバック A から OS 側に戻ろうとする直前に、
あたかも、コールバック B から戻ったように見せかけることができれば、
いい感じがしませんか?


393:ミミ
04/09/23 19:48:51
具体的な実装方法は、コールバック クロージャ B の
サンクとなる C 関数において、
コールバック開始時の継続をキャプチャしておきます。
また、「コールバック B のコンテキストである」という記録を
g_callbackContext グローバル変数に保持しておきます。

ここで、コールバック クロージャ A のサンクとなる C 関数から
OS 側に戻ろうとするとき、g_callbackContext を確認し、
それがコールバック A のコンテキストであれば、
そのまま OS 側に戻ります。
コールバック A のコンテキストでなければ、
そのコンテキストに対応する継続 (コールバック B 開始時にキャプチャしたもの)
を呼び出すことで、コールバック B のコンテキストを回復した上で
OS 側に戻ります。

少し問題なのは、コールバックの戻り値をどのように決定するかですが。。。


394:デフォルトの名無しさん
04/09/23 20:27:26
>>393
>問題は、ContA を呼び出し後に、コールバック A から呼び出し側に戻って
>しまうことが問題なのですよね。

Scheme の継続って、OS 側のコンテキストすら
捕獲できるほど強力だったか?

根源的に何か勘違いしていないか?



次ページ
最新レス表示
スレッドの検索
類似スレ一覧
話題のニュース
おまかせリスト
▼オプションを表示
暇つぶし2ch

5063日前に更新/286 KB
担当:undef