Scheme:イテレータスタイル

Scheme:イテレータスタイル

算譜の記 にあったちょっとしたテキスト処理。引用すると:

    <ID> <keyword1> <keyword2> ... <keywordi>

    のようなフォーマットのレコード行が複数あるテキストデータ(各行のkeyword の数は可変)を 

    <ID> <keyword1>
    <ID> <keyword2>
    ...
    <ID> <keywordi>

    のように ID と <keyword> との対を1行とするテキストデータに変換したい

Haskellだと2行でいけるらしい。Schemeではそうはいかない。

  (use srfi-13)
  (port-for-each (lambda (x)
                   (let ((y (string-tokenize x)))
                     (unless (null? y)
                       (for-each (lambda (z)
                                   (format #t "~a\t~a\n" (car y) z))
                                 (cdr y)))))
                 read-line)

SRFI-13のstring-tokenizeと、非標準のport-for-each, read-lineを使ってる。

これをコーディングしてて思ったのだが、繰り返し処理って普通、 「これこれの各要素に対してこの処理をする」と考えるのに対し (英語でも "for each element of this collection, do this procedure")、 Schemeのfor-eachやmapは先に処理が来て次に集合が来る。 複数の集合へのmap処理を考えてのことだろう。 (英語ならmapの場合は "map this procedure on (each element of) this collection" とも言えるけど)。

処理をインラインでlambdaで書く場合、どうしても複数行に渡ることが 多く、なんとなく思考の流れとテキストが一致しないんだなあ。

Rubyのイテレータ、集合.each { 処理内容 } のような順序の方が 直感的に書いてくのに良いように思う。特に使い捨てのスクリプトを 書くときなんかは。

但しそれだと複数のコレクションに対するマップ操作は書きにくい。

 print map { ($id, @keys) = split /\s/; map { "$id $_\n" } @keys } @data;
 (for-each (lambda (l) (for-each (cut print (car l)" "<>) (cdr l)))
           (port-map (cut string-split <> #/\s+/) read-line))

Arcでは 手続き以外のオブジェクトも適用可能にしようというアイディアがある。 例えばベクタをオペレータの位置に持って来て引数にインデックスを渡して 要素を取り出すとか。

  ('#(1 2 3) 1) ==> 2
  ("abc" 1) ==> #\b
  (apply "abc" '(2 1 0)) => '(#\c #\b #\a)

Gaucheにもこのアイディアを入れようかと思っていて、具体的には object-applyみたいなメソッドを定義しておくと、そのオブジェクトが applyされたときにそれが呼ばれると。

  (define-method object-apply ((obj <vector>) (index <integer>))
    (vector-ref obj index))

これで、

  (define-method object-apply ((obj <vector>) (mapper <procedure>) (proc <procedure>))
    (mapper proc obj))

とかしておいたら、Ruby的なイテレータの書き方もできるかもしれん。


こんにちは。 Backus' FFP systemにある Metacomposition Rule というのをからめると、なにか面白いものができそうな 気がするんですが、具体的なこれだ!というのが思いつきません。 どうでしょう。 --SHIMADA@2002/09/03 20:17:17 PDT

↑FFP system、なるほど、この規則でもって シーケンスというデータが評価可能な式へとliftされるわけですな。 でもシーケンスの最初をオペレータとしてしまっているのは… もともとリストの最初を特別扱いするのはLispでは 組込み機能みたいなもんなんで、あんまり嬉しくないかも。 --Shiro (2002/09/04 02:45:12 PDT)

難しいシステムですねぇ。apply と ':' が区別がよくわからないでいます。--nobsun (2002/09/04 05:00:41 PDT)

  (define (seqapply fs x)
     (map (lambda (f) (f x)) fs))

  (define (seqcompose fs x)
     (fold (lambda (f y) (f y)) x fs))

とかじゃだめかな


Last modified : 2012/02/07 08:32:12 UTC