Lispの力?

たまにはネタにマジレス

を見て、これくらいの処理ならふつーの言語(C的syntaxと言う意味で)でも十分わかりやすい。

でもLispならどういう表現があるだろうかと考えてみました。

で、とりあえずrubyならこんな感じ?

$tamuken = 100
open("geinin.csv") do |f|
  f.each_line do |line|
    name, power, photo = line.split(",")
    if $tamuken < power
      death(name, power)
      puts "は東京で売れている芸人なので抹☆殺しました"
    else
      puts "は東京で売れてない芸人なので見逃しました"
    end
  end
end

豊富なsyntax sugerのおかげで結構すっきり。これ以上簡潔にするにはどうしたら...

そしてGauche的仮想言語に直訳

(define *tamuken* 100)
(let1 contents (read-from-file "geinin.csv")
  (dolist (line (string-split contents #\newline))
    (match-let1 (name power photo) (string-split line ",")
      (if (< *tamuken* power)
        (begin
          (death name photo)
          (print name "は東京で売れている芸人なので抹☆殺しました"))
        (print name "は東京で売れてない芸人なので見逃しました")))))

密度が濃いな〜という感じ。
とりあえず条件分岐を手続きに分離してみるか

(dolist (line (string-split (read-from-file "geinin.csv") #\newline))
  (match-let1 (name power photo) (string-split line ",")
    (death-if (< *tamuken* power) name photo)))

(define (death-if p name photo)
  (if p
    (begin
      (death name photo)
      (print name "は東京で売れている芸人なので抹☆殺しました"))
    (print name "は東京で売れてない芸人なので見逃しました")))

メインな処理がちょっとすっきり。Lispじゃないとif文一つをわざわざ別関数にする気が起きないのは自分だけかもしれないけどね。

あとは読み込んだcsvを分解するという、どうでもいいところが目立っているのが気にくわないので、適当にマクロをでっち上げてみる。

(with-csv "geinin.csv" ","
  (death-if (< *tamuken* ($ 1)) ($ 0) ($ 2)))

(define-macro (with-csv file sep . body)
  (let ((lines (gensym)) (line (gensym)))
    `(begin
       (let1 ,lines (string-split (read-from-file ,file) #\newline)
         (dolist (,line ,lines)
            (define ($ i) (list-ref (string-split ,line ,sep) i))
            ,@body)))))

フィールドの値をawk的に取得できるように。繰り返しも隠蔽。これならやりたいことが一目瞭然!
これがPaul Grahamが言ってたLispの力なのか。高階関数による手続きレベルでの抽象&マクロによる構文レベルでの抽象...

でもマクロは綺麗とは言い難いけどね。そんなものはどこかへ隠してしまえばいいのだ!
でもよくよく考えてみるとrubyでも

with_csv("geinin.csv") do |row|
  death_if($tamuken < row[1], row[0], row[2])
end

って書こうと思えば書けるじゃん!
Lisp初心者&信者の俺乙。