(apply-generic op . args)

教育者, 将軍, 栄養士, 心理学者, 親はプログラムする. 軍隊, 学生, 一部の社会はプログラムされる. - 計算機プログラムの構造と解釈 序文

Common LispライブラリShellyを試してみた

MakeやRakeみたいなことが出来るLispライブラリShellyを試してみました。 おもしろいので貴方も試してみましょう(今回は一回もエディタを開いていないので、Emacsじゃないと、、、みたいなことは一切ないよ!!!)。

Shellyのサイトはこちら.

昔シェリーというイタリア人と付き合っていた事があって、Shellyという単語をみて懐かしいなーと思ったのが切っ掛けです(実話).

Common Lispは素晴らしい言語ですが縁が無い方が結構おられると思いますので、処理系のインストールから始めてみましょう。 以下、環境はMacOSX 10.9.2です。

Common Lispのインストール

Common Lispに限らず、Lisp族は沢山の処理系が存在するのでまず,どの処理系を使うのか選ばなくてはいけません。 今回はModernCommonLisp 第1回 Common Lisp処理系のインストールを参考に、Clozure CLを選択します。

~ iori:λ brew search clozure
clozure-cl
~ iori:λ brew install clozure-cl

こんだけ.

ライブラリを利用するためにQuciklispをインストールする

Rubyでいうgemとかそういうの。 これもインストールは簡単で

~ iori:λ wget http://beta.quicklisp.org/quicklisp.lisp
~ iori:λ ccl
Welcome to Clozure Common Lisp Version 1.9-r15758  (DarwinX8632)!
? (load "quicklisp.lisp")
? (quicklisp-quickstart:install :path ".quicklisp/")
? (ql:add-to-init-file)

こんだけ.

Shellyをインストールする

http://shlyfile.org/ に書いてある

$ curl -L http://shlyfile.org/shly | perl - install
$ PATH=$HOME/.shelly/bin:$PATH

を実行するだけ

なんか試してみる

~/work iori:λ mkdir shelly
~/work iori:λ cd shelly
~/work/shelly iori:λ echo '(defun fib (n) (if (< n 2) n (+ (fib (- n 2)) (fib (- n 1)))))' > shlyfile
~/work/shelly iori:λ shly fib 10

55

わーい、RakeとかMakeみたいなことがCLで出来たぞ!

Turbolinksを有効にしたままでangularjsを使用する

Turbolinks and Angularjs

最近はangularjsとRails4の組み合わせであそ、、、仕事しています。 まだまだangularjs触り始めて数日ですが、Turbolinksを有効にしているとng-showなどが画面遷移した際に上手く動かなかったのにハマったので、解決方法を自分用にメモ。

htmlからng-appを削除する

普通(?)はhtmlタグに

<html ng-app='MyApp'>

とか書くと思うんですが、これを削除します。

<html>

app.js.coffeeでbootstrapする

 window.App = angular.module('myApp', ['ngResource'])
$(document).on('ready page:load', ->
  angular.bootstrap(document.body, ['myApp'])
)

2~4行目を追記することで、turbolinkを有効にしていてもangularjsがbootstrapingされるので正常にng-showなどが動作しました。

備考

まだそこまでガッツリangularjsで書きまくっている訳ではないので、なにか問題でるかもしれませんが、

  1. inputに名前を入力
  2. /api/hoge/fugaにgetしてその名前が既に存在しているかチェック
  3. 既に存在していたら「その名前は既に使われています」みたいなalertを表示

くらいのは上記の方法でも正常に動作しました。

Good Luck!

werckerで自分のBOXを作ってみた

werckerで自分のBOXを作ってみました。 割りと簡単だったのでみんなももっと作るといいと思った(自分達のプロジェクトに最適なBOXって中々ないよね)。

作ったリポジトリはこちらです。 https://github.com/iori/box_iori_wercker

やったこと

  • Ruby2.1.1のインストール
  • ImageMagickのインストール

作り方

  • GitHubで専用のリポジトリを作る
  • WerckerとGitHubをいつもどおりに連携する
  • この辺を参考に、wercker-box.ymlを作成してPushする
  • MyApp -> 今作ったアプリ -> Settings -> Admin -> PublicAppにチェックを入れてSave

f:id:Iori_Nishizawa:20140316133050p:plain

  • AddDeployTargetでWerckerDirectoryを選択する

f:id:Iori_Nishizawa:20140316133251p:plain

  • DeployTargetNameになんか適切な名前をいれてSaveする

f:id:Iori_Nishizawa:20140316133327p:plain

  • 普段通りにBuildして、Buildが終わったらDeployする

f:id:Iori_Nishizawa:20140316133421p:plain

  • 無事デプロイが終われば、BOXに自分のBOXが出てくる!

f:id:Iori_Nishizawa:20140316133457p:plain

Rubyで無名再帰

http://kouyatakao.hatenablog.com/entry/2014/02/28/152153

を書いてて、あれ?Rubyって無名再帰どうすんの?と思って調べたらできたのでメモ

class Proc
  def self_curry
    self.curry.call(self)
  end 
end

def fib_closure
  cache = []
  lambda{|f,n| cache[n] ||= n <= 1 ? n : f.call(f, n-2) + f.call(f, n-1) }
end

fib_o = fib_closure
fib_o.self_curry.call(1000) # => 43466557686937456435688527675040625802564660517371780402481729089536555417949051890403879840079255169295922593080322634775209689623239873322471161642996440906533187938298969649928516003704476137795166849228875

Rubyでフィボナッチのメモ化

仕事つかれたー、なんかリフレッシュしたーい。 なんて時によくフィボナッチを書いて、それをメモ化してにやにやします。 で、今も仕事の合間にそんなことをしていたのですが、需要少しはあるかなーと記事にしてみた。

普通にフィボナッチ

irb(main):001:0> def fib n
irb(main):002:1>   n <= 1 ? n : fib(n-2) + fib(n-1)
irb(main):003:1> end
=> nil
irb(main):006:0* fib 10
=> 55
irb(main):007:0> require 'benchmark'
=> true
irb(main):011:0> Benchmark.measure { fib 40 }
=> #<Benchmark::Tms:0x007f84932ef3c8 @label="", @real=31.694596, @cstime=0.0, @cutime=0.0, @stime=0.04000000000000001, @utime=31.199999999999996, @total=31.239999999999995>

40とかすると遅いですね。

メモ化

irb(main):014:0* def fib_memo n
irb(main):015:1>   @memo ||= []
irb(main):016:1>   @memo[n] ||= n <= 1 ? n : fib_memo(n-2) + fib_memo(n-1)
irb(main):017:1> end
irb(main):020:0> Benchmark.measure { fib_memo 40 }
=> #<Benchmark::Tms:0x007f8493305858 @label="", @real=3.5e-05, @cstime=0.0, @cutime=0.0, @stime=0.0, @utime=0.0, @total=0.0>

メモ化、サラマンダーよりはや〜(ry 1000でも1瞬で終わります。

さって仕事しよう。

werckerで既存のRailsプロジェクトを突っ込んだら結構ハマった話し

追記: 2014/03/23

Werckerにバグ報告したら直してくれた :)

最近はクラウドCIサービスでテスト回したりするのがどんどん普及していますね。 TravisCIやCircleCIやCodeShipなどなど。。。 その中でプライベート・リポジトリでも現在は無料で使えるWerckerがどんどん注目を集めていると感じます。

そんな訳で、色々なWercker始めようぜ!って記事を参考に、GitHubにある既存のRailsプロジェクトがPushされたりしたらWercker上でTurnipとRspecが走るところまでやってみました。

が、、、超絶ハマった!!!

Gemのバージョンが古いとhoge.soが見つからないと怒られる

$ bundle exec rake db:schema:load RAILS_ENV=test
rake aborted!
libruby.so.2.0: cannot open shared object file: No such file or directory - /cache/bundle-install/ruby/2.0.0/gems/rmagick-2.13.2/lib/RMagick2.so

ひたすらこんなエラーがでる。 で、これはまぁRMagickなんでまた別件なんですけど、エラーがでるgemのバージョンが古かったら、gemによってはこのエラーがでる。 でないgemもあった。 pgとかは0.17.1にUPしたら動いたけど、最初入れてたバージョンだと古くて↑のようなエラーが出ましたね。

取り敢えずgemのアップデートをしたら問題なく動きましたよっと。

どう頑張ってもRMagickは使えなかった

$ bundle exec rake db:schema:load RAILS_ENV=test
rake aborted!
libruby.so.2.0: cannot open shared object file: No such file or directory - /cache/bundle-install/ruby/2.0.0/gems/rmagick-2.13.2/lib/RMagick2.so

rmagickは2.13.2が最新なんだけど、どう頑張っても出来なかった。 ただgemを入れているだけなら問題ないんだけど、carrierwaveで生成したuploaderで

include CarrierWave::RMagick

ってしていて、これがあるとどうしても↑のエラーがでる。

で、結局rmagickの使用を辞めてminimagickにしました。 これだと問題なくwerckerエラー吐かなかった(´・ω・`)

結論

  • ちゃんとgemのアップデートしましょう
  • rmagickはなんか使えなかった

誰か「それはお前の使い方が悪いんじゃボケ」とかあったら教えて下さいませ。

実用CommonLisp -第二章読了-

PAIP2章読了しました。 二日酔いで死んでいたので2日ほど空いてしまった。 生活リズム崩れまくって、今日は徹夜して一気に戻す作戦なので眠い目を擦りながら朝5時くらいからPAIPってた。

2章はDSL書きましょうって内容でした。 うーん面白い。

https://github.com/iori/paip

第2章 簡単なLispプログラム

2.1 英語のサブセット用文法

2章では任意の英文を生成するプログラムを書く。 英語のごく小さなサブセット用の簡単な文法が示される。

文 => 名詞句 + 動詞句
名詞句 => 冠詞 + 名詞
動詞句 => 動詞 + 名詞句
冠詞 => the, a, ...
名詞 => man, ball, woman, table, ...
動詞 => hit, book, saw, liked, ...

この記述は、技術的には文脈自由な句構造文法(context-free phase-structure grammar)と呼ばれる。 基礎となるパラダイムは生成統語論(generative syntax)と呼ばれる。 この文法は次のように理解すれば良い。 文(Sentence)を生成したい場合は、名詞句(Noun-Phrase)と動詞句(Verb-Phrase)を生成できる。 名詞句が特定された場合は、その代わりに冠詞(Article)と名詞句を生成する。 冠詞が特定された場合はthe, a, またはその他の冠詞を生成する。 取り囲んでいる単語にかかわらず、どの部分にも規則を適用するので、形式論としては「文脈自由」である。 規則が全体としてある言語の分の完全な集合と、その上に非文の完全な集合を定義しているので、考え方は「生成的」である。 この規則を使用して単一の文を導出してみよう。

2.2 成功法による解法

句構造文法を使用して任意の文を生成するプログラムを開発する。 成功法は、各々の文法規則を別のLisp関数によって表現することである。

(defun sentence () "文" (append (noun-phrase) (verb-phrase)))
(defun noun-phrase () "名詞句" (append (Article) (Noun)))
(defun verb-phrase ()  "動詞句" (append (Verb) (noun-phrase)))
(defun Article () "冠詞" (one-of '(the a)))
(defun Noun () "名詞" (one-of '(man ball woman table)))
(defun Verb () "動詞" (one-of '(hit took saw liked)))

(defun one-of (set)
  "Pick one element of set, and make a list of it."
  (list (random-elt set)))

(defun random-elt (choices)
  "Choose an element from a list at rondom."
  (elt choices (random (length choices)))) 

プログラムは問題なく実行される。 しかしLispによる定義はオリジナルの文法規則よりも読みづらい。 さらに複雑な文法規則を扱う場合に、この問題が自体を悪化させる

名詞句 => 冠詞 + Adj* + 名詞 + PP*
Adj* => Φ, Adj + Adj*
PP* => Φ, PP + PP*
PP(前置詞句) => Prep + 名詞句
Adj(形容詞)  => big, little, blue, green, ...
Prep => to, in, by, with, ...

この表記法で、Φ は空の選択を示す。カンマはいくつかの選択肢があることを示す。 アスタリスクは特異なものではなく、Lispで紹介したものと同様にシンボル名の一部である。 PP*はPPが0回以上繰り返すことを示す。 これは数学者Stephen Cole Kleeneの名をとって「Kleen star」(clean-Eと発音する)表記法と呼ばれる。 アスタリスクで終わる名前は、アスタリスクが付かない元の名前が0回以上繰り返されることを表している。

(defun Adj* ()
  (if (= (random 2) 0)
    nil
    (append (Adj) (Adj*))))

(defun PP* ()
  (if (random-elt '(t nil))
    (append (PP) (PP*))
    nil))

(defun noun-phrase () (append (Article) (Adj*) (Noun) (PP*)))
(defun PP () (append (Prep) (noun-phrase)))
(defun Adj () (one-of '(big little blue green adiabatic)))
(defun Prep () (one-of '(to in by with on)))

重要な点は、最初は単純な関数だったものが、今ではかなり複雑になっていることである。 理解するためにはdefun,(),case,if,quote,評価の順序などのLispの規則を知る必要がある。 文法規則の実装は、理想的には言語学の規則だけを使うべきだ。 大きな文法を開発する場合は、問題はさらに悪化して、文法を記述する人はますますLispに依存しなくてはならない。

2.3 ルールベースによる解法

プログラムを実装する上での代替え案は、文法規則を書きやすくすることに集中して、それらを処理する方法は後で考えることである。 オリジナルの規則を見てみよう。

文 => 名詞句 + 動詞句
名詞句 => 冠詞 + 名詞
動詞句 => 動詞 + 名詞句
冠詞 => the, a, ...
名詞 => man, ball, woman, table, ...
動詞 => hit, book, saw, liked, ...

各規則は、左辺部の1つのシンボル、矢印、右辺部から構成される。 面倒なことには、右辺部が2種類あることである。すなわり、名詞句 → 冠詞+名詞のように連結されたリストの場合と、名詞 → mann, ball, ...のように選択可能な単語のリストの場合である。 これに対応するには、全ての規則が右辺部に可能性のあるもののリストを持てば良い。 例えば、連結されたリスト「冠詞+名詞」は(Article Noun)のようなLispのリストで表せる。 したがって、規則のリストは次のように表せ、ルールベースによる関数はこうなる。

(defparameter *simple-grammar*
  '((sentence -> (noun-phrase verb-phrase))
    (noun-phrase -> (Article Noun))
    (verb-phrase -> (Verb noun-phrase))
    (Article -> the a)
    (Noun -> man ball woman table)
    (Verb -> hit took saw liked))
  "grammar:文法 / A grammar for a trivial subset of English.")

(defvar *grammar* *simple-grammar*
  "The grammar userd by generate. Initially, this is *simple-grammar*, but we can switch to other grammars.")

(defun rule-lhs (rule)
  "規則の左辺部を取得する"
  (first rule))

(defun rule-rhs (rule)
  "規則の右辺部を取得する"
  (rest (rest rule)))

(defun rewrites (category)
  "ある文法カテゴリに対する書き換え(右辺部)の全てを調べる"
  (rule-rhs (assoc category *grammar*)))

(defun mappend (fn the-list)
  "Apply fn to each element of list add append the results."
  (apply #'append (mapcar fn the-list)))

(defun generate (phrase)
  "Generate a random sentence or phrase."
  (cond ((listp phrase)
         (mappend #'generate phrase))
        ((rewrites phrase)
         (generate (random-elt (rewrites phrase))))
        (t (list phrase))))

2.4 進むべき2つの道

結論としてはルールベース(今風でいうとDSL)のほうがいいよ。

ルールベースの考え方は、余分なステップを踏むので小さい問題に対しては仕事量が大きくなるけれど、多くの場合、修正や拡張が容易になる。 AIの問題のほとんどはこの記述が適している。

この章の感想

この章では英文の生成プログラムを2つの方法で作成し、DSLは小さい問題では仕事量は増えるが、拡張性・修正容易性・ドメインの規則だけを使ってプログラムを記述できる、などの良さを伝えている。

この章で特に印象的だったのは2.2節の

重要な点は、最初は単純な関数だったものが、今ではかなり複雑になっていることである。
理解するためにはdefun,(),case,if,quote,評価の順序などのLispの規則を知る必要がある。
文法規則の実装は、理想的には言語学の規則だけを使うべきだ。
大きな文法を開発する場合は、問題はさらに悪化して、文法を記述する人はますますLispに依存しなくてはならない。

という部分です。 プログラミングやソフトウェア開発を学ぶ本で、「その言語に依存することは問題である」と言い切っている本は中々ないのではないでしょうか?

AIという分野が題材とはいえ、これは最近の「特定の言語を深く知っている俺って凄い」みたいな(一部の人達の)風潮に疑問を感じていた僕にとっては、なんだかとっても賛同したくなる一文でした.