Gauche:refj-gauche

Gauche:refj-gauche

refj-gauche

動機

  1. ブラウザでマニュアル探すのが面倒になってきた。
  2. でも GaucheRefj の仕組みが提供されている。
  3. こいつを利用させてもらっちゃおう

最初は get した HTML を Htmlprag を使って何とかしようとしてたし、 マニュアルの HTML が変わる可能性を考えると ある程度そうした方がいいのだが、案の定挫折した。 sxpath とか使い込んでみないとなんとも。 ってなわけで単純にテキスト処理したのであった。

ソース

":";exec gosh -b $0 "$@"
(use rfc.http)
(use rfc.uri)
(use util.list)

(define *server* "www.shiro.dreamhost.com")
(define *uri* "/scheme/gauche/man/")

(define (refj keyword)
  (receive (status header body)
      (http-get *server*
                #`",|*uri*|?l=jp&p=,(uri-encode-string keyword)"
                :no-redirect #t)
    (let1 uri (cadr (assoc "location" header))
      (receive (scm spc)
          (uri-scheme&specific uri)
        (receive (svr uri qry frg)
            (uri-decompose-hierarchical spc)
          (receive (status header body)
              (http-get svr #`",|uri|#,|frg|")
            (let ((pat? (string->regexp #`"<A NAME=?",|frg|?">"))
                  (end? (string->regexp "^<A NAME=?"IDX??d+?">")))
              (call-with-input-string body
                (lambda (in)
                  (let loop ((ln (read-line in)))
                    (if (pat? ln)
                        (let loop2 ((ln (read-line in))
                                    (doc (cons ln '())))
                          (if (end? ln)
                              (format #t "~a"
                                      (apply string-append
                                             (map (lambda (str)
                                                    (if (#/^(<[^>]+>)+?n/ str) ""
                                                        (apply string-append
                                                               (string-split str #/<[^>]+>/))))
                                                  (reverse doc))))
                              (loop2 (read-line in)
                                     (cons (string-append ln "?n") doc))))
                        (loop (read-line in)))))))))))))

(define (main args)
  (for-each (lambda (key)
              (print "-----------------------")
              (refj key)) (cdr args)))

;; Local variables:
;; mode: scheme
;; end:

使い方

cut-sea@mokili> ./refj-gauche.scm call/cc 'even?' any
-----------------------
Function: call/cc proc
[R5RS]
現在の継続を手続き (継続手続き) にパッケージ化して、それを引数として
procを呼び出します。procが戻ったら、その返り値がcall/ccの
値となります。作成された継続手続きがどこかで0個または複数個の引数を伴って呼ばれたら、
あたかもcall/ccから戻ったかのように実行が継続されます。その場合、
call/ccは、継続手続きに与えられた引数を複数の値として返します。

ファーストクラスの継続はSchemeの最も特徴的な機能のひとつですが、それを
十分に説明するにはこの本の余白は狭すぎます。適切なドキュメントを参照してください。

Gaucheはわずかの例外を除いて、完全な継続をサポートしています。つまり継続は通常
無制限のエクステントを持ちます。しかし、継続がCコードからの「コールバック」
---SchemeがCで書かれたコードを呼び出し、それが再びSchemeコードを呼び出した場合---
で作られたら、その継続のエクステントはコールバックが呼び出したCコードに戻るまでと
なります。エクステントの切れた継続を呼ぼうとするとGaucheはエラーを報告します。
これは根本的な制限であり、おそらく解決されないでしょう。

なお、コールバックコードから有効な継続を呼ぶことは常に可能です。また、
高階関数を使うmapやfor-each、applyといった手続きは
Cからのコールバックを使っておらず、この制限の影響を受けません。

おそらく、そのようなコールバック内で無制限のエクステントを持つ継続を作る必要というのは
あまり無いでしょう。Gauche組み込みの機能では、以下のようなコードがCからのコールバックで
呼び出されます。さらに、外部のCライブラリを使った場合、例えばGUIツールキットからの
コールバックなどはこの制限を受けるでしょう。
write、display、formatから呼び出される
write-objectメソッド (6.18.8 出力参照)。
バッファードポートから呼び出されるfillerとflusher手続き。
(9.27 gauche.vport - 仮想ポート参照)。


-----------------------
Function: even? n
[R5RS]
整数nがそれぞれ奇数または偶数なら#tを返します。
非整数を渡すとエラーになります。

&nbsp;(odd? 3)     => #t
(even? 3)    => #f
(odd? 3.0)   => #t

-----------------------
Function: any pred clist1 clist2 ...
[SRFI-1]
clist の各要素に pred を適用し、predが偽でない
値を返したら直ちにその値を返します。
predが偽でない値を返す前にリストの要素を使いきってしまったら
#fが返ります。

cut-sea@mokili> 

BUG

十分テストしてないので、まだまだいろいろあるだろう。

TODO

とりあえず、当面の欲求は満たされたのでやるかどうか分かんないけど。

  1. &nbsp; や &quot; などのコードをどうにかしたい
  2. コードをもうちょい分かりやすくしようよ

コメント

Shiro(2005/01/13 13:56:31 PST): ちなみに、infoという関数を使うとインタプリタから infoファイルが引けます:GaucheRefj:info。これをもう少し使い易く してもいいかも。

cut-sea(2005/01/13 16:21:00 PST): あ、あったんですね。
ブラウザ叩くより良いかも。しばらく使ってみることにします。

ねるWiki:ねる (2005/01/13 23:31:31 PST): GaucheのInfoが少々遅いので、infoをcdb化して早くしたinfo-cdb.scmをつかってます。
あと、emacsであればinfoの枠組みを使うのが楽のようで、ねるWiki:NelDiary:2004-10-20の下の方のようなelispを書いておくと割と快適です。

More ...