#:g1: outputの紹介

Posted 2014-03-19 15:00:00 GMT

(LISP Library 365参加エントリ)

 LISP Library 365 の79日目です。

outputとはなにか

 outputは、複雑になってしまったFORMATに対して、既存の制御構造と組み合せてシンプルに書けるように考案された出力系のユーティリティです。
1980年のinfo-lispmメーリングリストに下記のようなRMSからの投稿があります:

To: INFO-LISPM at MIT-AI
Subject: FORMAT
From: RMS at MIT-AI (Richard M. Stallman)
Date: Mon ,5 May 80 22:13:00 EDT
Since FORMAT is now as hairy and ugly as TECO, I have written a more Lispy replacement, RMS;OUTPUT >. It may be more verbose for simple things, but ought to yield more readable code for anything complicated since you use the ordinary Lisp control constructs.

面白そうなのでソースを探していたのですが、MIT CADRや、LMI Lambda等のLispマシンのio1ディレクトリ以下にoutputというファイルがあったので眺めてみるに、件のメールの内容と一致するところが多いので恐らく同一のものだと思います。

パッケージ情報

パッケージ名output

インストール方法

 Lispマシン(MIT CADR System 99やLMI Lambda)のソースからoutput.lispを探してきて移植しましょう。
ちなみに私がCommon Lispに移植してみたものがありますので、良かったらどうぞ。

試してみる

 o〜が各データ形式に対応した出力関数で、それらを纏める際にはoutputや、さらにFORMATに引数として渡すことを意図したoutfmtを利用します。

OCHAR
(ochar #A)
;>>  A
;=>  NIL
OFLOAT
(ofloat 10000000 10)
;>>  1.e7
;=>  10000000
ONUM
(onum 10000000 10 16 :signed T :commas T)
;>>       +10,000,000
;=>  10000000
OPRINT
(oprint 'a)
;>>  A
;=>  A
OSTRING
(ostring "foo bar baz")
;>>  foo bar baz
;=>  "foo bar baz"
PLURAL
(plural (onum 2) " apple")
;>>  2 apples
;=>  " apples"
TAB
(output T
  (fresh-line)
  (ostring "hello")
  (tab 30 :pad-char #.)
  (terpri))
;>>  hello.........................
;>>  
;=>  NIL
BREAKLINE
指定した長さより出力する文字列が長かったり、カーソルのポジションが上限に達した場合に改行を入れるというもの。改行した後に入れる文字列も指定可能。
(output T
  (terpri)
  (fresh-line)
  (dotimes (i 100)
    (breakline 10 "->"
      (ostring "."))))
;>>  
;>>  ..........
;>>  ->........
;>>  ->........
;>>  ->........
;>>  ->........
;>>  ->........
;>>  ->........
;>>  ->........
;>>  ->........
;>>  ->........
;>>  ->........
;>>  ->........
;>>  ->..
;=>  NIL
PAD
埋め草の制御
(pad (16 :pad-char #0)
  (onum 10000000 10 0))
;>>  0000000010000000
;=>  NIL
OUTFMT
FORMATに渡す引数を作るらしい。
(apply #'format t
       (outfmt
         (fresh-line)
         (dotimes (i 10)
           (pad (20) (onum (expt 10 i) 10 0 :commas T))
           (terpri))))
;>>                     1
;>>                    10
;>>                   100
;>>                 1,000
;>>                10,000
;>>               100,000
;>>             1,000,000
;>>            10,000,000
;>>           100,000,000
;>>         1,000,000,000
;>>  
;=>  NIL
本当にこういう使い方で合ってるのかは謎ですが…
OUTPUT
第一引数にストリームを指定、FORMATと同じくTなら*standard-output*に出力、nilなら文字列が得られます。
(output T
  (fresh-line)
  (dotimes (i 20)
    (pad (30) (onum (expt 10 i)))
    (terpri)))
;>>                               1
;>>                              10
;>>                             100
;>>                            1000
;>>                           10000
;>>                          100000
;>>                         1000000
;>>                        10000000
;>>                       100000000
;>>                      1000000000
;>>                     10000000000
;>>                    100000000000
;>>                   1000000000000
;>>                  10000000000000
;>>                 100000000000000
;>>                1000000000000000
;>>               10000000000000000
;>>              100000000000000000
;>>             1000000000000000000
;>>            10000000000000000000
;>>  
;=>  NIL

まとめ

 今回は、outputを紹介してみました。
実際のところ署名がないのでRMSのコードかどうかは分かりませんが、ORやANDを多用しているところがRMSっぽい気もします。

 ちなみに上述のCommon Lispへ移植したものについてですが、Lispマシンだと、カーソルの位置をストリームに問合せることができたようです。しかし、Common Lispではそこまで仕様で決まってはおらず処理系依存機能となるので、SBCLで適当に処置しています(gray-stream等を利用すれば若干ポータブルかも)

comments powered by Disqus