mokeheheのScheme日記

ツッコミ、添削大歓迎です。いろいろ教えてください。

2008-01-03

[] Caesar cipher

TBS | 404 NotFound記念に、anarchy golf - Caesar cipherを解く:

; 1を足す
(define (1+ x) (+ 1 x))

; 文字を回転させる
(define (rotate-char c start-char end-char n)
        (let ((cc (char->integer c))
              (st (char->integer start-char))
              (ed (char->integer end-char)))
          (if (and (<= st cc) (<= cc ed))
              (integer->char (+ (modulo (+ (- cc st)
                                           n)
                                        (1+ (- ed st)))
                                st))
            c)))

; 文字列の文字ごとに関数を適用する
(define (string-map fn str)
        (list->string
         (map fn
              (string->list str))))

; 文字を暗号化
(define (caesar-cipher-char c n)
        (rotate-char (rotate-char c #\A #\Z n)
                     #\a #\z n))

; 文字列を暗号化
(define (caesar-cipher str n)
        (string-map (lambda (c) (caesar-cipher-char c n))
                    str))

(let ((str (read-line (current-input-port) #t)))
  (dotimes (i 26)
    (print (caesar-cipher str i))))
  • エレガントさのかけらもない
  • Schemeで数式を扱うと超わかりにくいな…

はてな記法に悩まされている

スーパーpre記法(シンタックス・ハイライト)が怪しい。バッククォート「`(」やスター「*)」などがあると中身が表示されなかったりする?スペースをつけると動作が変わる。謎。

[] Practical Common Lisp第7章 マクロ

わずか7章でもうマクロキター

  • 条件式やガベージコレクションなど、Lispをオリジナルにする多くのアイディアが他の言語に影響を与えた一方、引き続き Common Lisp を特別なものにしている特徴は、マクロのしくみだ。
  • しかし、違う意味のマクロが広まってるおかげで、Common Lispマクロがいかにすばらしい特徴かを説明するのに苦労する
  • プログラミング言語を、言語コア+標準ライブラリと定義すると、理解しやすく実装しやすくなる
    • しかし、本当の利点は表現力にある
    • 言語をライブラリだけと考えれば、その言語は簡単に拡張できるでしょ?
  • マクロを使えば、新たな文法を作ることができる
when と unless
  • if の then, else には式をひとつしか与えられないので、それ以上の式を与えたい場合 progn を使う必要がある
    • if と progn を一緒にやってくれるのが欲しい
    • それ when でできるよ
(defmacro mywhen (condition &rest body)
  `(if ,condition (progn ,@body))) 
  • 取るに足らないマクロの例だけど、利点はでかい
cond
  • if ... else が複数つながると、インデントも深くなるし醜い
  • cond でスッキリ
and, or, not
  • and は偽が現れた時点で、orなら真が現れた時点で、残りの評価を打ち切る、のでマクロで定義される
ループ
  • Lispの25の特殊オペレータは直接ループ構造をサポートしてはいない、マクロが構築している
  • do: 汎用
    • dolist, dotimes: リスト、回数ループに特化したもの
  • loop: ミニ言語ぽい、Lispらしからぬ、英文ぽいループ用マクロ
    • 賛否両論
dolist と dotimes
do
(do (variable-definition*)
    (end-test-form result-form*)
  statement*) 
  • do を使ってフィボナッチ数の計算
オールマイティなloop
(loop
  body-form*)  
  • 複雑な使い方:
    • (loop for i from 1 to 10 collecting i) ==> (1 2 3 4 5 6 7 8 9 10)
    • (loop for x from 1 to 10 summing (expt x 2)) ==> 385
    • (loop for x across "the quick brown fox jumps over the lazy dog" counting (find x "aeiou")) ==> 11
  • (loop for i below 10 and a = 0 then b and b = 1 then (+ b a) finally (return a))
  • 22章で詳しく説明
  • loopはwhenやifよりちょっと複雑なだけで同じマクロだから、もしloopが標準ライブラリになかったとしても自分で実装できるよ
"Practical Common Lisp"を読んでる方:

[] Practical Common Lisp第6章 変数

http://gigamonkeys.com/book/variables.html

変数の基礎
レキシカル変数クロージャ
(let ((count 0)) #'(lambda () (setf count (1+ count))))
動的変数(特殊変数
  • defvar, または defparameter
  • 慣習的に名前を *...* とする
  • defparameter は常に値のセットを行う、defvar は変数が未定義の場合だけ
  • 実際には、defvar を使うべき
  • defvar や defparameter で定義した変数は特殊となり、動的変数になる。名前で見分けないと酷い目にあう。

よくわからん

定数
  • defconstant
  • 慣習的に名前は +...+
  • すでに定義済みの定数を違う値でもう一度定義しても値は変わらない
代入
  • setfマクロ
    • 格納先が変数の場合:setq 特殊オペレータ
  • ちょっとこれは理解不能だ~
(defun foo (x) (setf x 10))

(let ((y 20))
  (foo y)     ; foo の結果はyには反映されず
  (print y))  ; => 20

setf とか setq の、f とか q ってなんなのさ?

一般化された代入
  • 配列ハッシュテーブル、リスト、ユーザ定義データ構造も値を保持できる
  • どれも setf で値をセット可能
他の方法
  • incf, decf
  • push, pop, pushnew
  • (rotatef a b)
    • (let ( (tmp a)) (setf a b b tmp) nil)
  • (shiftf a b 10)
    • (let ( (tmp a)) (setf a b b 10) tmp)

Write Yourself a Scheme in 48 hours

no title

以前はHaskellSchemeもろくにわからなかったので、さわりだけでちんぷんかんぷんだったけど、今なら読めるかも。読むリストに追加しておこう。

トラックバック - http://sicp.g.hatena.ne.jp/mokehehe/20080103