2008年10月24日金曜日

整数を3けた区切り形式の文字列に変換する関数

この間の日曜日、基本情報処理技術者試験を受けに行ってきました。 合格するかどうかは正直微妙…

そこでこんな設問が

午後の問題 問6: [プログラムの説明] 金額を表すときのように、整数を3けた区切り形式の文字列に変換する関数 convert である。(以下略)
           表 変換例
┌────┬────────────┐
│  整数  │3けた区切り形式の文字列│
├────┼────────────┤
│1234567 │1,234,567               │
│ -57482 │-57,482                 │
│     63 │63                      │
│-999999 │-999,999                │
└────┴────────────┘

C言語での問題だったけど、なんとなく Lisp で解いてみた。
# 別に解答間違ったからその腹いせにじゃあないです :-(


((lambda (int &optional (interval 3) (comma ","))
   (reverse
    (with-output-to-string (*standard-output*)
      (with-input-from-string 
          (in (reverse (princ-to-string (abs int))))
        (do ((i 1 (1+ i)))
            ((not (listen in)))
          (princ (read-char in))
          (if (and (zerop (mod i interval))
                   (listen in))
              (princ comma)))
        (if (minusp int)
            (princ "-"))))))
 -123456789)                    ; => "-123,456,789"

でも CLer なら一行で十分だよね、というオチ。

(format nil "~:D" -123456789)   ; =>"-123,456,789"

2008年10月23日木曜日

elispでarglist関数っぽいの

「xyzzyでarglist関数っぽいの 」[その1][その2] のおまけ。

何でこんなの作ったんだろう…

;;; for Emacs Lisp
(defun arglist (def)
  (unless (keymapp def)
    (let ((argstr (car (help-split-fundoc (documentation def) def))))
      (if argstr
          (format "%s" (cdr (car (read-from-string argstr))))
        (help-function-arglist def)))))

(arglist 'arglist)        ; (def)
(arglist 'lambda)         ; "(ARGS [DOCSTRING] [INTERACTIVE] BODY)"
(arglist 'if)             ; "(COND THEN ELSE...)"
(arglist 'ctl-x-4-prefix) ; nil

参考にした関数: describe-function-1 (lisp/help-fns.el)

elisp では関数定義の引数とドキュメントに書かれている引数が異なる場合があるので、そのときは後者を優先します。ややこしいなあ。

(help-function-arglist 'lambda)
=> (&rest cdr)
(car (help-split-fundoc (documentation 'lambda) 'lambda))
=> "(lambda ARGS [DOCSTRING] [INTERACTIVE] BODY)"

2008-10-25T00:40:33+09:00 [追記]

read-from-whole-string 関数 (lisp/thingatpt.el ファイルで定義されている) は標準で使えるものでないので read-from-string に変更。

とりあえず「特殊」だということは分かった

CLのスペシャルに秘められた罠(?)」より

関係あるっぽい記述を見つけたのでメモ。

SPECIAL-OPERATOR-P - CLHS

Notes:

Historically, this function was called special-form-p. The name was finally declared a misnomer and changed, since it returned true for special operators, not special forms.

注意: (適当訳) 古くから、この関数は special-form-p と呼ばれていた。 この関数はスペシャル・フォーム(リスト)でなく、スペシャル・オペレータ(シンボル)が与えられる場合に真を返すことから、この名前は最終的に誤った名前であると認められ改定された。

仕様を決めていた中の人も勘違いしていたようで。

しかしなぜ勘違いしたのか、なぜ長い間改定がなかったのかは、気になる。 CLtL2 には special-form-p しかないなあ。ANSI-CL で変更されたのかな。

ちなみに xyzzy でも special-form-p しかないのでサクッと定義。 もちろん LISP パッケージの中ですよ、奥さん。

(in-package :lisp)

(export '(special-operator-p))

(defun special-operator-p (symbol)
  "Returns true if symbol is a special operator,
otherwise, returns false."
  (special-form-p symbol))

2008年10月21日火曜日

読書感想文

Shibuya.lisp テクニカルトーク #1 (Ustream.TV)での配信をリアルタイムで見てました。

# 途中あまりの眠気に落ちたのはナイショ

Lispを使った実例を見れた(聞けた)ところ、これが良かった。 Lispで作られたアプリの例をあまり知らないので。

一番印象に残ったのはmitamex4uさんの「俺Lisp」の話。 ケータイで動くREPLを見てみたいです。

もう少し文章書いていた気がするんだけど、気に入らない部分を添削し てたらこんなに短くなってしまったよ。

2008年10月19日日曜日

なんでだろう

「APIを叩く」って言葉は誰が言い出したんだろう。

「叩け(リクエストすれ)ば埃(レスポンス)が出る」みたいな意味合いだと思うが。 うまい表現だなあと思った。それだけ。


2008-11-01T03:46:40+09:00 [追記]

コンピュータ用語として「叩く」を取り上げていたページ

叩く - 通信用語の基礎知識
プログラミングに於いては、ハードウェアの接続されているI/Oポートにアクセスすることを "ポートを叩く" と表現する。
日本版 Jargon File
vt. プログラマが「叩く」ものはポートである。英語ではもっぱら `bashing' が使われるが、それと対応している。

まあ、スラングなんでしょう。

2008年10月15日水曜日

[xyzzy]外部コマンドの結果を文字列として出力する

command-substitutionという関数があります。けっこう便利。

上の関数を、バッファを介せずにCLの標準関数だけで作れないかなーと 思ってこんなものを書いてみた。まだまだ処理系依存。

やっていることは以下の3点

  1. 外部コマンドを呼び出して、結果をファイルに保存
  2. 保存したファイルの中身を文字列ストリームに流す
  3. ついでに右端の空白文字を取り除く
(defun cat (file &optional stream)
  "print file contents."
  (with-open-file (fp file)
    (do ((ch (read-char fp nil nil)
             (read-char fp nil nil)))
        ((null ch))
      (princ ch stream))))

(defun shell-command-to-string (command)
  "Execute shell command COMMAND and return its output as a string."
  (let ((outfile (make-temp-file-name "xyzzycmd-")))
    (unwind-protect
        (with-output-to-string (stream)
          (call-process command :output outfile
                        :show :minimize :wait t)
          (cat outfile stream))
      (delete-file outfile))))

(defun command-substitution (command)
  (string-right-trim '(#\SPC #\TAB #\LFD)
    (shell-command-to-string command)))
結果:
(command-substitution
 (format nil "ls -1 ~A"
        (merge-pathnames "*.exe" (user-homedir-pathname))))
=>
"C:/home/xyzzy/xyzzy.exe
C:/home/xyzzy/xyzzycli.exe
C:/home/xyzzy/xyzzyenv.exe"

(command-substitution "echo 舌足らずなブログ") => "舌足らずなブログ"

意図してなかったが日本語も通るようだ。

ちなみにshell-command-to-stringという関数名はEmacsから

後は

  • 一時ファイルを作成する関数 (make-temp-file-name)
  • 外部プロセスを処理する関数 (call-process)
がCLにあれば尚良いんだけど…

2008年10月14日火曜日

第20回CL勉強会@Lingrセルフ反省会

勉強会ログ g000001さんによる勉強会まとめ

前半: Let Over Lambda 概略 2~3章まで (g000001さん)

筆者が別だから当然だけど、OnLispとは違った側面でマクロを使ってい る印象。マクロの導入部分はどうしても他のマクロ本と似たり寄ったり の説明になってしまうのかも。ちょっと勘違い。

xyzzyはインタプリタとしてしか使ってないから、コンパイルする際の マクロ展開やら変数補足やらを気にしたことなんてなかったなあ。

後半: CL永続化入門 (onjoさん)

GoogleDocsによるスライドはとても見やすかったです。

xyzzyが吐き出すダンプファイルもLispのデータを保存している例では なかろうかと思ったり思わなかったり。

(si:dump-image-path)  ; => "C:/home/xyzzy/xyzzy.wxp"

次回の勉強会は10/25です。 (10/18はShibuya.lispのためお休み)