Gauche:メールは読みましたが、現在メール送信の標準的なAPIは有るのでしょうか。 無ければ、sendmailを使うのが今のところ無難でしょうか。
マクロ中でdefineを使用するとマクロ使用の周りのスコープの束縛に作用する処理系と、マクロ自体でスコープが閉じる処理系があるようなのですが、どちらが正しい挙動なのでしょうか?
具体的には
(define-syntax foo (syntax-rules () ((foo) (define x 100))))
というマクロを定義して、トップレベルで
(foo) (display x) (newline)
した場合、アンバウンドエラーになる処理系(scheme48,Gambit-C,mzscheme,sisc)と100が表示される処理系(Gauche,scm,guile)があります。
このマクロfooはxに対する束縛を挿入しますが、このxは実質的にリネームされると考えると前者が正しいように思えます。しかし、それならばマクロ中のdefineは常に内部定義という事になり、R5RSがマクロの項でトップレベルのdefineに言及している理由がわからなくなります。
Shiro(2007/05/21 06:44:49 PDT): 「内部定義」になるのではなく、どちらの解釈でも 挿入されるdefineはトップレベルだけれど、xがグローバルにリネームされるか どうかという違いである、ってことじゃないでしょうか。 (R5RSのp14冒頭の "may or may not introduce binding" は文脈から、「トップレベルの bindingかどうか」ではなく、「hygienityが考慮すべきbinding」を問題にしている ように私には思えます。)
定義される変数をマクロ呼び出し時に与えてやれば曖昧さは回避できます。
(define-syntax foo (syntax-rules () ((foo var) (define var 100)))) (foo x) x ;; => 100
Scheme48系統の方式の場合、マクロ展開時に挿入される変数が外からは実質アクセス 出来ないことになりますが、そのマクロ展開時に同時に挿入されるコードからは アクセスできるわけなんで、例えば次のようなコードでxを外部から隠蔽するのに 便利といえば便利ですね。
(define-syntax foo (syntax-rules () [(foo proc) (begin (define x 100) (define (proc) x))])) (foo bar) (bar) ;; => 100
質問者(2007/05/21 07:46:28 PDT): Scheme48系統の挙動について、挿入された変数にアクセスできないことから、マクロでスコープが閉じていると考えていたのですが、スコープ自体はGauche方式と同様、マクロ使用と変わらないんですね。Shiroさんの洞察が正しかった証明
((lambda () (newline) (foo)))
マクロでスコープが閉じていれば問題ないはずですが、Scheme48系統でもすべてエラーになりました。 トップレベルのdefineはset!としての顔もありますから、必ず衝突回避をした方がいいとはいえないでしょうね。R5RSではdefineは(letrecに変換できる内部定義の方はともかく、トップレベルの方は)束縛コンストラクタであるとは書かれていないから、マクロの挿入する束縛にあたらない、という解釈になるのでしょうか。いかなる場合も衝突を許さず、必ず回避させるScheme48系統と、プログラマが望むであろう衝突は許すGauche系統といえますね。
ちなみにGauche系統も挙動が2種類あって、内部定義としての(define x 0)の後に(foo)を書くと、衝突回避をしてくれるGaucheと、duplicate bindingになるscm・guileに分かれます。
Shiro(2007/05/06 00:37:25 PDT): 思いがけず盛り上がっているので別ページに移します→ Gauche:部分スプリット
Scheme:マクロ:CommonLispとの比較にあるような多くの差異が、この選択から発生しているようで、大きな設計上の変更のように思えます。static scopeのどのような利点が、このような選択をさせたのだと思いますか?
ということで、funarg 問題を解決するためのようです。funarg 問題については http://en.wikipedia.org/wiki/Funarg_problem 。When the precedure is eventually invoked, the intuitive effect is that the the <body> in an environment consisting of (a) the environment in which the lambda-expression had been evaluated to produce the procedure, plus (b) the pairing of the identifiers of the <identifier list> with the arguments supplied to the procedure. The pairings (b) take precedence over the environment (a), and to prevent confusion no identifier may appear twice in the <identifier list>. The net effect is to implement ALGOL-style lexical scoping [Naur], and to solve the funarg problem [Moses].
Shiro(2007/02/12 20:04:50 PST): まあそういうことです。一番最初のSchemeの論文も、 "SCHEME is essentially a full-funarg Lisp" で始まっています。
もうすこしくだいて説明すると、それまでのLispにおけるlambda式とか 変数束縛の実装っていうのはわりと実装の都合からデザインされてきてたところが あったんですが、関数自体をファーストクラスオブジェクトとして扱いはじめると デザインの歪みが見えて来ていました(それがfunarg問題)。 一方、Scheme開発の動機となった研究において、lambda式をクロージャと みなせば、それは単なる関数の表記法ではなく、むしろ制御の流れやプログラムの 構造化の根本となる概念ではないかっていう発見があったわけです。 言語のひとつの機能としてlambda式があるのではなく、lambda式が一番下に あって残りの言語は全てそれをレゴブロックみたいに組み合わせれば作れるじゃないか ってことですね。レキシカルスコープはそこから自然に導かれた機能だと思います。
ナンバープレイスの問題を解きたいのですが、要素を確実に減らす方法ではとけるのですが、 バックトラックがわかりません。ambを使わないバックトラックを教えてくだ さい
Lisp:よくある正解やLisp:Geometryで、Lispの最終兵器として挙げられる 実行中のプログラムに対するハックですが、Gaucheでのシンプルなサンプルは無いでしょうか?
(use gauche.threads) (use gauche.net) (define *port* 5678) (define echo-filter (lambda (val) val)) (thread-start! (make-thread (let1 server (make-server-socket 'inet *port* :reuse-addr? #t) (rec (main) (let* ((sock (socket-accept server)) (in (socket-input-port sock)) (out (socket-output-port sock))) (let loop ((istr (read-block 4096 in))) (cond ((eof-object? istr) (socket-close sock) (main)) (else (display (echo-filter istr) out) (loop (read-block 4096 in))))))))))5678番ポートへの入力をエコーします。手抜きのために同時に1接続しか処理できませんが、それは気にしないでください。telnet localhost 5678などというようにtelnetで接続すると、入力がそのまま送り返されてくるはずです。で、実行中のコードを差し替える例として、echo-filterを再定義してみます。echo-filterは最初はvalues相当なのですが、これを差し替えると入力をフィルタした結果を出力できます。次のコードをgoshに入力すると、次の瞬間から入力が大文字でエコーされるはずです。
(use srfi-13) (define (echo-filter istr) (cond ((string-complete->incomplete istr) => string-upcase) (else istr)))実行するとこのように意図したように動きます。string-upcaseをstring-titlecaseなどで置き換えたりしていろいろ遊んでみると楽しいかもしれません。
$ telnet localhost 5678 Trying 127.0.0.1... Connected to localhost. Escape character is '^]'. this is a pen. (これは入力) this is a pen. (これは出力) <<<ここでecho-serverを再定義> the quick brown fox ju (入力) THE QUICK BROWN FOX JU (出力)
Emacs でメタ/コントロールキーを多用するのにキーボードのお勧めありますか? またノートPCではどうでしょうか。
◆◆◆ About Scheme ◆◆◆という文章があります。Schemeについての理解も未だ浅い上にCommon Lispについては全然知らないので、その両方を知っていてSchemeを好む方の声を聞きたいです。(2006/12/13 19:57:49 PST)
Shiro(2006/12/15 03:50:04 PST): 両方仕事で使い込んでいる身としては、黒田さんの話は もっともだと思いますよ。…って言うとSchemerから怨差の声が上がりそうですが、 ちょっと落ち着いて、黒田さんが「言っていること」と「言っていないこと」を よく考えてみましょう。
まず、いつ何のために言語を使うか、という視点が重要です。今すぐに、 今後数年以上のスパンで使う業務システムを組むなら、私はCLを使います。 もしGaucheを使ったとしたら、その業務システムのメンテを他人に振るのが (CLほどには)容易でないので、数年は面倒を見なくちゃならない。さらに Gaucheの側に非互換な仕様変更を持ち込んで業務システムを動かなくしちゃうと まずいんで、Gauche側の設計の自由度も減ってしまう。あまり良いことが ありません。なので、今Gaucheを使うとしたら、自分が継続して面倒を みられるプロジェクトが主となります。黒田さんが言っているのはそういうことです。
ただね、もう一つ考えなくちゃならないのは、10年あるいは20年後にどの 言語でプログラムしているかということです。この点について黒田さんは 特に何も言っていない。まあCLはその時も残っているでしょうが、 CLの仕様は策定時に考えられた機能は豊富に盛りこんでいるものの、 その後に広く使われるようになったコンポーネントはカバーしてない ですよね (例:ネットワークとか多言語化とか)。今後10年で、CLの 現在の仕様がカバーしていない部分というのは、今の仕様がカバー している部分よりずっと大きくなるでしょう。もちろんCLはCLでそれに 追従しようとするでしょうが、カバーすべき範囲の大きさを考えれば、 Schemeだって条件は大して変わらない。こっから先は多分私と 黒田さんで見解が分かれるところだと思いますが、私はCLの現在の 仕様が足を引っ張ることになるんじゃないかという気がします (例えば、stringがcharacterのmutableな配列である、という仕様)。
まあそれはそれとしても、今の仕様が10年後に十分であるとはとても 思えないわけで、10年後に「今のCLのように使える」言語を手にする ためには今からそれに向けて色々実験しておく必要があるわけですな。
マクロの話については色々面白いので、別ページにします →Scheme:マクロ:CommonLispとの比較。
リストを受け取り、そのリストの要素を先頭から順に返す(全ての要素を返したら、再びリストの先頭を返す)関数を返す関数cycleを作成したいのですが、どのように書いたらよいですか。 --coze
こんな感じです。
gosh> (define c (cycle '(1 2 3))) ; 1 2 3 1 2 3 ... を返す関数 c gosh> (c) 1 gosh> (c) 2 gosh> (c) 3 gosh> (c) 1 gosh> (c) 2
(use srfi-1) (define (cycle ls) (let1 cls (apply circular-list ls) (lambda () (begin0 (car cls) (set! cls (cdr cls))))))
(define (cycle ls) (make-generator (cut for-each <> (apply circular-list ls))))
(define (cycle ls) (let ((l (length ls)) (i 0)) (lambda () (begin0 (list-ref ls i) (set! i (modulo (+ i 1) l))))))
(use srfi-1) (define (cycle xs) (let1 xs (apply circular-list xs) (lambda () (pop! xs))))
(use gauche.parameter) (define (cycle ls) (let1 i (make-parameter -1 (lambda (j) (modulo (+ j 1) (length ls)))) (lambda () (list-ref ls (i (i))))))
最近のEcmaScriptにはジェネレータという機能があります。それと同じような感覚で使えるものをSchemeで実装してみようとこんなものを書きました…
とあるフリーサーバにGaucheをインストールしました。 そのサーバではLinuxが使われてます。 一般ユーザの権限で/procにアクセスできないようになっているせいで、GCがスタックの開始アドレス取得に失敗する模様です。(おそらくセキュリティ上の都合でしょう。) 何か簡単な迂回策があれば教えて下さい。GCライブラリの中の話なので本来ならそちらに質問すべき内容かとは思いますが、英語でちゃんと説明できる自身がないので…。
skr こんな感じです。
(combination-maker '(a b c)) ((a b) (a c) (b c))
(define (combination-maker seq) (if (< (length seq) 2) '() (append (map (lambda (x) (list (car seq) x)) (cdr seq)) (combination-maker (cdr seq)))))
試しに
(combination-maker '(a b c)) ((a b) (a c) (b c))
でも
(combination-maker '((a b) (c d) (e f))) ((#0=(a b) #1=(c d)) (#0# #2=(e f)) (#1# #2#))
何が起きているのか、どなたか教えて頂けないでしょうか?
(write (combination-maker '((a b) (c d) (e f))))
(Scheme:Procedureに移動しました。)
(define str "<a href=\"./foo.png\">foo.png</a><br><a href=\"./index.html#30\">>>30</a><br>") (regexp-replace-all #/<a href=.*>(>\;>\;\d{1,4})<\/a>/ str "\\1")だと、結果が、">>30<br>"になってしまいます。gemma
(define str "<a href=\"./foo.png\">foo.png</a><br><a href=\"./index.html#30\">>>30</a><br>") (regexp-replace-all #/<a href=[^>]*>(>\;>\;\d{1,4})<\/a>/ str "\\1")
やってみると、こんな感じになります。--ふじさわ
gosh> (define ht (make-hash-table 'equal?)) ht gosh> (hash-table-put! ht cons 1) *** ERROR: no applicable method for #<generic object-hash (0)> with arguments (\ #<subr cons>) Stack Trace: _______________________________________ 0 (hash-table-put! ht cons 1) At line 3 of "(stdin)" 1 (hash-table-put! ht cons 1) At line 3 of "(stdin)" 2 (hash-table-put! ht cons 1) At line 3 of "(stdin)"
gosh> (define ht (make-hash-table 'eq?)) ht gosh> (hash-table-put! ht cons 1) #<undef> gosh> (hash-table-get ht cons) 1 gosh> (define ht2 (make-hash-table 'eqv?)) ht2 gosh> (hash-table-put! ht2 cons 2) #<undef> gosh> (hash-table-get ht2 cons) 2
Shiro(2006/04/15 15:48:30 PDT): ここでの問題はequal? ではなくて (手続き同士の equal? は eq? と同じです)、equal-hashtableを作るために必要なハッシュ関数が 手続きに対しては定義されていない、というエラーです。
equal-hashtableに使われるハッシュ関数hashには、ハッシュ値がプロセスイメージと 独立である(そのため永続テーブルに保存したり別プロセスに送ったりできる)という 属性もあるので、単純に オブジェクトのアドレス値からハッシュ値を計算するといった方法が使えないのです。
この「ハッシュ値がプロセスイメージと独立」という性質はCommon Lispの sxhash関数に倣ったものです。ただ、単一プロセス内でequal-hashtableを 使う限りにおいては不要な性質であり、選択の余地が無い今の実装は 使いづらいですね。ぼちぼちhashtable回りも改善してゆきたいと思います。
ssax:xml->sxmlの逆変換はsxml:sxml->xmlですか? 次のようにすると"*TOP*"などがタグになってしまってうまくいかないのですが・・・。
(tree->string (sxml:sxml->xml (ssax:xml->sxml (open-input-string "<a></a>") '()))) ;; => "<*TOP*><a/></*TOP*>"
Gaucheの正規表現(#//)を便利に使わせて頂いております。 Perlで/gを指定したときのように、一行中にある複数のマッチした文字列を取り出す方法はございますでしょうか? es (2006/04/11 04:35:07 PDT)
(use srfi-42) (define (rxmatch-all re str) (let loop ((r '()) (str str)) (let1 m (rxmatch re str) (if m (loop (let1 nmatch (rxmatch-num-matches m) (if (= nmatch 1) (cons (m 0) r) (append! (reverse! (list-ec (: i 1 nmatch) (m i))) r))) (m 'after)) (reverse! r))))) (rxmatch-all #/./ "abc") ; => ("a" "b" "c") (rxmatch-all #/.(.)/ "abcde") ; => ("b" "d")
線型代数の本で一次変換のことを読んで興味がでてきました。そしてOpenGLが行列変換を使って種々の変換を行っているらしいことまではわかりました。まずは何を用意したらWindowsで動かせるでしょうか?MinGW版のGaucheで動かしたいです。 sasagawa
pa$ や map$ などの、おしりの$がへんてこりんに見えます。$をつけている理由はなんですか?
とおる。(2006/03/14 09:58:28 PST): そもそもストリームの中で副作用のあることなんかするなというのもあるかもしれませんが……。
要素が取り出されるときにグローバルな状態が変わるようなストリームを作ります。 計算されたタイミングが分かるようにデバッグプリントを入れています。
gosh> (use util.stream) #<undef> gosh> (define *c* 0) *c* gosh> (define (s) (set! *c* #?=(+ 1 *c*)) (stream-cons *c* (s))) s
で、
gosh> (define ss (s)) #?="(stdin)":4:(+ 1 *c*) #?- 1 ss
ここでは(当然)1 度だけ評価されますが、 stream-car すると
gosh> (stream-car ss) #?="(stdin)":4:(+ 1 *c*) #?- 2 #?="(stdin)":4:(+ 1 *c*) #?- 3 2
なぜか (s) が 2 度呼ばれているようなんですが、 これはなぜでしょうか?
(%make-stream (delay (if (not (stream? (s))) ;; (s)の評価1 (error "attempt to stream-cons onto non-stream") (cons *c* (s))))) ;; (s)の評価2普通はstream式はidempotent(何度評価しても結果は同じ)なので見過ごされて いたんだと思います。普通stream式は呼ばれるとstreamを作って返すので、 今までstream-consは呼ばれるたびにstreamをひとつ余分に作成してた わけですな。これをfixすると少し性能もあがるかも。
;(time (stream-ref (stream-iota -1) 100000)) ; real 1.124 ; user 1.130 ; sys 0.000fix後
;(time (stream-ref (stream-iota -1) 100000)) ; real 0.650 ; user 0.650 ; sys 0.000 100000
リファレンスのlengthのところをみると、
listが循環リストの場合、この関数は無限ループします。
となっていますが、
gosh> (define ls '(1 2)) ls gosh> (set-cdr! ls ls) #<undef> gosh> ls #0=(1 . #0#) gosh> (length ls) *** ERROR: proper list required, but got #0=(1 . #0#) Stack Trace: _______________________________________ 0 (length ls) At line 27 of "(stdin)" 1 (length ls) At line 27 of "(stdin)" gosh> (length+ ls) #f
となります。#0=(1 . #0#) は真性リスト(proper list)だと思うのですが違うのでしょうか?
Windows/MinGWのGaucheを使っています。
(define (nan) (/ 0 0)) (display (= 0 (nan))) (display (if (= 0 (nan)) #t #f))
というコードをgoshで実行すると
#t#f
と表示されます。なぜこの二つは違う結果になるのでしょうか?またそもそもNaN==0はTrueなのでしょうか?
Shiro(2006/02/23 01:16:01 PST): NaNの扱いはまだ正式に決めていないので、このへんの 振るまいはまだ当てにしないで下さい。NaNの扱いはsrfi mailing listや comp.lang.schemeで何度も出ているのですが、すっきりした結論が出ていないのです。 だいたい議論はこんな感じです:
案としては、確かこんなのが出てたと思います。
個人的には最後の案でいいかなという気がしてます。あ、(= NaN 0)は#fに なるべきだと思います。バグですね。
『ハッカーと画家』p.187 に
Python は Lisp ハッカーの多くが間違いだと思っている機能さえコピーしている。
とありますが、その機能とは何ですか? リスト内包表記があるんだから map や filter は 必要ないというのをぱっと思い浮かんだのですが、それとは違いますよね。
また Python 関係なしに、Lisp の間違い(だとハッカーが思っている)機能には、どのような ものがあるのですか?
even style な stream で、stream を返す関数が全体を (delay (force ...)) で囲まなければならない理由が分かりません。 囲まなくても動くように見えますが、メモリリークを防ぐためとかの理由でしょうか。
(define (map2 func strm) (if (nil2? strm) nil2 (cons2 (func (car2 strm)) (map2 func (cdr2 strm)))))とかやっちゃうと、delay される前に nil2? で force されちゃうから、odd stream みたいに一つ先の要素まで評価しちゃうってことか。 ということで合ってるでしょうか?
> (define x '(* 2 3)) (define x '(* 2 3)) #<unspecified> > (car x) (car x) * > (eval x) (eval x) 6
gosh> (define x '(* 2 3)) (define x '(* 2 3)) x gosh> (car x) (car x) * gosh> (eval x) (eval x) *** ERROR: wrong number of arguments for #<subr eval> (required 2, got 1) Stack Trace: _______________________________________ 0 (eval x) At line 3 of "(stdin)" 1 (eval x) At line 3 of "(stdin)"なぜでしょう?
(eval x (interaction-environment))と書くのが正解です。
Win9x系を使っているので、socket-input-port,socket-output-portが使えません。そこで、gauche.vportを使ってあらためてportとして使えるようにしようとしているのですが、エラーとなってしまいます。
*** ERROR: output port required, but got #<<network> 011360E0>
かなり根本的なところで勘違いしているような気がします。 出力ポート、入力ポートとして使えるオブジェクトはいったいどのような条件を備えていればよいのでしょうか? 実際に書いたコードはこんなのです。
#!/usr/bin/env gosh (use gauche.net) (use gauche.vport) (use gauche.uvector) (define-class <network> (<buffered-input-port> <buffered-output-port>) ((socket :init-keyword :socket))) (define-method flush ((self <network>) a b) (socket-send (ref self 'socket) (u8vector->string a))) (define-method fill ((self <network>) a) (let ((temp (string->u8vector (socket-recv (ref self 'socket 800)))) (write-block temp) (length temp) ))) (define socket (make-client-socket 'inet "www.w3.org" 80)) (define network (make <network> :socket socket)) (display "GET / HTTP/1.0?r?n" network)
(use gauche.net) (use gauche.vport) (use gauche.uvector) (define (sock-output-port socket) (let ((putb (lambda(ch) (socket-send socket (string ch)))) (puts (lambda(str) (socket-send socket str)))) (make <virtual-output-port> :putb putb :puts puts))) (define (sock-input-port socket) (let ((getb (lambda() (string-byte-ref (socket-recv socket 1) 0))) (gets (lambda(siz) (socket-recv socket siz)))) (make <virtual-input-port> :getb getb :gets gets))) (define socket (make-client-socket 'inet "localhost" 80)) (define out (sock-output-port socket)) (define in (sock-input-port socket)) (display "GET / HTTP/1.0?r?n?r?n" out) (read-line in) (socket-close socket)
gauche.vportとcall/cc(とgauche.selectorとgauche.net)を使って、 空のsocket-input-portからreadしようとしたタイミングで、 そこまでの処理を一旦継続として保存してから中断し、 他の処理を行うようなソケットサーバを書いていたのですが、 gauche.vportの中で作った継続を外から辿ろうとすると、
*** ERROR: a continuation is thrown outside of it's extent: 0x81842a0
と言われて、辿れませんでした。 (<buffered-input-port>と<virtual-input-port>の両方を試して、両方駄目でした。) 確かに、vportはCの部分を通過しているので、辿れないのも分かるのですが……。 やっぱり無理でしょうか。 -- nekoie(2005/11/25 03:25:02 PST)
u8vectorが広く採用されるに従って、不完全文字列の存在意義が薄れているような気がしますが、長期的に不完全文字列は廃止方向ですか?
Kahuaの部分継続はすごく便利なので、Kahua以外でも使いたいです。Gauche本体に取り込まれたりはしないのでしょうか? -- nekoie(2005/11/16 12:35:02 PST)
システムの環境変数操作について。unsetenvやclearenvなど削除系の関数はマニュアルに載っていないのですが、実際はsys-unsetenv関数が使えるようです。マニュアルの漏れですかね? -- ふじさわ(2005/11/15 03:32:45 PST)
ShiroさんのWiLiKiのページ履歴を差分表示するまで気付きませんでした。 いつの間に? [skr]
Collection cの中身が1つだけとわかっている場合、
(fold (lambda (x _) x) '() c)
なんてやって値を取り出しているんですが、他にもっとスマートな方法は無いでしょうか。 Sequenceなら(ref s 0)でおしまいなんでしょうけど。 ちなみに、dbi/dbdの結果から、値を取り出したいのです。katsujiro
(define-method collection-car ((self <collection>)) (call-with-iterator self (lambda (end? next) (if (end?) #f (next)))))
SRFI:1 の lset って遅くないですか?集合演算ごとに線形時間か、それ以上かかりそうな……
caseシンタックスは、キーと一致するclauseを判定するのにeqv?を使いますが、eqv?ではなくequal?が必要なときはどうしたらいいでしょうか? もちろんcondを使って、自分でcondのtest clauseにequal?を並べることはできますが、(1)キーの生成に副作用がある場合にはプログラマが明示的にローカル変数を作らないといけない、(2)副作用がないとしても同じキーを並べるのが面倒、という理由で、equal?で比較するcaseがあると便利だと思うのですが。自分でシンタックスを追加してもいいとはいえ、そういうものが標準で用意されていないのは、なにかいいやり方が別にあるから?
(match var ((or "abc" "def" "ghi") ....) ;;; 文字列のいずれかにマッチ ((or '(abc) '(def) '(ghi)) ...) ;;; リテラルリストにマッチ )
(define-syntax case* (syntax-rules (else) ((_ (exp ...) clauses ...) (let ((pred (exp ...))) (case* pred clauses ...))) ((_ pred (else e1 e2 ...)) (begin e1 e2 ...)) ((_ pred ((c1 c2 ...) e1 e2 ...)) (if (find pred '(c1 c2 ...)) (begin e1 e2 ...))) ((_ pred ((c1 c2 ...) e1 e2 ...) clause clauses ...) (if (find pred '(c1 c2 ...)) (begin e1 e2 ...) (case* pred clause clauses ...)))))こんな具合に使います。
(case* (pa$ string=? var) (("abc" "bcd" "cde") "ABCDE") (("zyx" "yxw" "xwv") "VWXYZ") (else "HOGE!!"))でも、実際のコードでこれを使ったことは1、2度しかなかったと思います。どうもcaseって中途半端な感じがしてたんです。そうか、util.matchって手がありましたね。当時はまだGaucheにはなかったですけど。
このWiLiKiでどなたかがボソっとおっしゃっていたような記憶がありますが。
Lispの処理系なんかによくある機能だと思うんですけど、エラーが起きたときの環境でreplのプロンプトがでたりするのって、Scheme(Gauche)ではどうなんでしょうか。
再現性の低いバグとかの解析とか、1回だけの処理で起きたエラーからとりあえず復帰させて処理を継続させるとか、いろいろ便利(?)(katsujiro)
cygwinでGauche-glが使えるというのは、cygwinのX Window上という事でしょうか? Windowsそのもの(書き方が変で済みません)で使う方法があったら教えて頂けないでしょうか?
自分の書く関数は let* からはじまることがよくあります. これは避けた方がいいという話があるみたいですけど, 理由がわかりません. ええと, 「手続き型発想」をしてるつもりはさらさらなくて, 「f(x) = (1/Z) exp L, Z = √(2πσ^2), L = - D/(2σ), D = (x - μ)^2」 みたいに, ごちゃごちゃした式の部分部分へ「名前」をつけて 見やすくしてるだけのつもりです.
(let* ((a (f0 x y)) (b (f1 x y)) (c (f2 a b)) (d (f3 a b))) ...)f0, f1, f2, f3が全て副作用無しであるとすれば、本来、f0とf1の呼び出し、 およびf2とf3の呼び出しはそれぞれ順不同で良いはずですが、let*が使われて いることから自動的にf0→f1→f2→f3という順番が強制されてしまいます。 処理系としては、次のように書いてもらった方がずっと最適化がやりやすいです。
(let ((a (f0 x y)) (b (f1 x y))) (let ((c (f2 a b)) (d (f3 a b))) ...))
くだらないことなんですが、zero?という述語、なぜ用意されているんでしょう? (= x 0)で十分だと思うんですけど。(eq? x '())と同じ意味のnull?が用意されているのに対応して、zero?が存在しているのかしら?
ここを読んでいて感じたのですが、他言語コミュニティと比較して、Schemer内の職業プログラマ比率は低めなのでしょうか。 いや、そんなことは無い、実プロダクトでもバリバリ使っているよ!という事例がありましたら、教えていただけるとうれしいです。学習の励みになります。
また逆に、「今はまだ実プロダクトでは厳しいかもしれない。でも、○○が整備されればイケるんじゃないかな?」といったご意見でもうれしいです。それはそれで、目標ができて励みになりますから。
http-get 問題の解決に関して Gauche に libcurl を組み込んだらいいんじゃないかと思ったのですが、その方法がわかりません。適当なドキュメントはありますでしょうか?
Gaucheでhttpクライアントを作ろうとしています。 このとき http-get 関数に :Accept-Encoding "gzip, compress" を 指定して圧縮されて受け取ったデータを展開するにはどうすればよいでしょうか?
javaみたいにgzipのストリームがあれば便利なんですが、ストリームどころか 素のgzipのユーティリティも見当たらないようです。 知ってる方お知恵をお貸し下さい、おながいします。
どーゆう風に強いの?
Shiro: これは長くなりそうな話題だな。議論がおもしろくなってきたら 別ページに移すかも。
私はSchemeラヴな人間なので、言語としてはSchemeの単純さと統一性を長所と考え、 Common Lisp?の仕様の大きさや過去をひきずったライブラリを短所と考えます。 一方、処理系の充実度、安定度ではCommon Lisp?の方に一日の長があり、 例えば業務でシリアスなアプリケーションを書く場合、私は今なら Common Lisp?を選びます。ネイティブコンパイルがちゃんと出来て、 それをかりかりチューニングできて、デバッガやプロファイラなどのツールが 充実してて、という環境は重要です。
かつてはCommon Lisp?の方がライブラリも豊富だし、とも思っていたのですが、 最近はSchemeもSRFI等のおかげでライブラリが充実しつつあり、さらに 自分が欲しいと思ったライブラリをGaucheに実装している関係上、 「欲しいものにすぐ手が届く」感はGaucheでプログラミングしている時の方が 強くなっています。もっともGaucheのライブラリはまだ全然足りませんが。
C言語の関数とは別物?