2013年4月22日月曜日

[SICP][Haskell] ニュートン法で平方根を求める

ニュートン法を使って平方根を求める処理をHaskellで書いてみた。

コード

prec = 0.0001

mysqrt :: Double -> Double
mysqrt x = sqrt_iter 1 x x
  where sqrt_iter guess last_guess x = if good_enough guess last_guess then
                                         guess
                                       else
                                         sqrt_iter (improve guess x) guess x
          where
            good_enough guess last_guess = (abs (guess - last_guess) / guess) < prec
            improve guess x = average guess (x / guess)
                  where average a b = (a + b) / 2

実行結果

*Main> mysqrt 2
1.4142135623746899
*Main> mysqrt 20000
141.42135623738412
*Main> 

SICPのSchemeのコードほぼそのまま。何のひねりもない。
Schemeよりは分かりやすいような気もするけど、この程度じゃあまり変らないよね...
Schemeで hoge? 、Common Lispで hoge-p と命名するような predicateな関数は、Haskellではどのように命名するのが一般的なんだろうか?


コードよりは、
  • ニュートン法とは?
  • どうしてニュートン法で平方根を求めることができるの?
の方が気になって、理解できるまで、いろいろ調べてしまった。
接線の方程式とか、微分とか、いろいろ忘れているなぁ。
たまには数学を再勉強しなきゃ。

参考

2013年4月21日日曜日

[SICP][Lisp]Gauche + Emacsで環境構築

今更だけど、SICP (Structure and Interpreter Computer Programming)を読み始めた。
この本では、Schemeが使われている。
自分でコードを書きながら、読み進めた方が楽しいので、
まずは、Scheme処理系の一つであるGauche+Emacsを使い、
REPLとコード補完できる環境を構築した。

OSはUbuntu、Emacsは自分でインストールしたEmacs 24.2を使用している。

Gaucheのインストール

gaucheはパッケージが用意されているのでapt-getでインストールする。
$ apt-get install gauche

quackとscheme-completeのインストール

パッケージのダウンロード

インストール先は ~/.emacs.d/gauche-el とした。
$ cd ~/.emacs.d/
$ mkdir gauche-el
$ cd gauche-el
$ curl -O http://www.neilvandyke.org/quack/quack.el
$ curl -O http://synthcode.com/emacs/scheme-complete-0.8.11.el.gz
$ gunzip scheme-complete-0.8.11.el.gz
$ mv scheme-complete-0.8.11.el scheme-complete.el

init.elの設定

emacsの設定ファイルinit.elにquackとscheme-completeの設定を追加する。
(add-to-path 'load-path "~/.emacs.d/gauche-el")
(setq quack-default-program "gosh")
(require 'quack)
(require 'scheme-complete)
;;(autoload 'scheme-smart-complete "scheme-complete" nil t)
;; auto-completeを使っているので不要
;; (eval-after-load 'scheme
;;   '(define-key scheme-mode-map "\e\t" 'scheme-smart-complete))
(add-hook 'scheme-mode-hook
  (lambda ()
    (make-local-variable 'eldoc-documentation-function)
    (setq eldoc-documentation-function 'scheme-get-current-symbol-info)
    (eldoc-mode)))
(setq lisp-indent-function 'scheme-smart-indent-function)

動作確認

Emacsを起動後、hello.scm を新規作成する。
(print "こんにちは、世界!")

hello.scmのバッファでC-c C-lを押下する。
mini-bufferで、以下を聞かれる。
それぞれデフォルトのままで良い。
Load Scheme file: (default hello.scm) ~/workspace/sicp/
Run Scheme (default "gosh"):

REPLが開き、hello.scmの実行を結果が表示される。


gosh> こんにちは、世界!
#t
gosh>


とりあえず、他に、以下のコマンドが分かればOK。
  • C-c C-e S式を評価する。
  • M-x run-scheme REPLを起動する。

eldocで関数の説明が表示されるし、コード補完もできる。
いつも使っているslimeとあまり違和感はないようで、なかなか便利だ。


参考

quack
http://www.neilvandyke.org/quack/

scheme-complete
http://synthcode.com/wiki/scheme-complete

auto-complete
http://cx4a.org/software/auto-complete/index.ja.html

SCIPのmobiファイル
https://github.com/twcamper/sicp-kindle

2013年4月7日日曜日

[Raspberry Pi]HUNCHENTOOT + Open JTalkでブラウザ経由で音声出力

Raspberry PiでHUNCHENTOOTが動くようになったので、ブラウザから入力したメッセージを音声出力するWebアプリを作ってみた。

たわいないアプリだけど、小さなRaspberry Piを使って、遠隔操作で音声出力できるのはなかなか楽しい。
デスクトップからRaspberry PiにSSH接続し、tmux + CCL + Emacs(Slime)で開発したが、この程度なら、特にレスポンスが遅いことはなく、ストレスはなかった。
やるなぁ。Raspberry Pi。

ソースはこちらから(https://github.com/takeisa/cl-webapp-talk.git)

動作に必要なLinuxパッケージ

  • open-jtalk
  • open-jtalk-mecab-naist-jdic
  • hts-voice-nitech-jp-atr503-m001

実行方法

  1. Clozure CL(CCL)で、(load "talk.lisp")する。
  2. ブラウザで http://〜:4242/talk を開く。
  3. メッセージを入力してsubmitする。
  4. Raspberry Piがしゃべる!

使用したCommon Lispライブラリ

全てQuicklispでロードできる。
HUNCHENTOOT
Webサーバ。
cl-who
HTMLの生成に使用。
trivial-shell
シェルコマンドの実行に使用。
OSに依存せずにシェルコマンドを実行できる。

ファイル

talk.lisp
HUNCHENTOOTを使ったWebアプリのコード
talk.sh
音声出力したいメッセージを書いたテキストファイルを読み込み、Open JTalkで音声合成後、音声出力するシェルコマンド

動作説明

やっていることは単純。
  1. ブラウザからメッセージを受けとる。
  2. メッセージが空だったら、音声出力しないで、入力画面だけ表示する。
  3. メッセージがある場合は、音声出力する。
  4. 音声出力したいメッセージを message.txt へ出力する。
  5. talk.shを実行する。
  6. talk.shはmessage.txtよりメッセージを読み込み、Open JTalkで音声合成する。
  7. 音声ファイル /tmp/message.wav を出力する。
  8. それを aplay で再生する。再生後は音声ファイルを消去する。

参考ページ

2013年4月6日土曜日

[Raspberry Pi]Clozure CL + Quicklisp で hunchentoot

RaspbianをインストールしたRaspberry PiでQuicklispを使いたかったのだけど、提供されているLispパッケージでは、
CLISP → quicklisp.lisp のロードでSIGSEGVエラー
ECL → quicklisp.lispをインストールできたが、setup.lispでエラー(だったかな?)

となって、どちらもNGだった。

困ったなーと、Google検索していて見つけたのが、こちらのページ。
Installing Clozure Common Lisp on the Raspberry Pi
http://lispm.dyndns.org/ccl
このページを参考に、Clozure CL(以下CCL) と QuicklispをRaspberry Piにインストールし、
Webサーバーであるhunchentootを動かしてみた。

以下、hunchentootを動かすまでの手順。





前提

Raspberry PiにインストールしたOSはRaspbian
ビルドに必須のパッケージsubversion, m4を追加でインストール済み
インストール先は ~/opt

CCLインストール

$ mkdir ~/opt
$ cd ~/opt
$ svn co http://svn.clozure.com/publicsvn/openmcl/trunk/linuxarm/ccl
$ cd ccl

cclディレクトリ直下に armcl がある。
'armcl' is an executable with the CCL runtime.
実行できる。

$ ./armcl
Welcome to Clozure Common Lisp Version 1.10-dev-r15791M  (LinuxARM32)!
? (quit)

このままだとsoft floatsなので、hard floatsにコンパイルオプションを変更してビルドする。

$ cd lisp-kernel/linuxarm/
$ emacs float_abi.mk → ◆どのように変更すれば良いかは見れば分かる
$ make clean
$ make

少し待つ。こちらのmakeはそれほど時間はかからない。
makeが終ったら、CCLをフルビルドする。

$ cd ../../ → cclディレクトリへ
$ ./armcl
Welcome to Clozure Common Lisp Version 1.10-dev-r15791M  (LinuxARM32)!
? (ccl:rebuild-ccl :full t)

しばらく待つ。
完了したら (quit)。
上記ブログによると、Saving a CCL Application が便利のようだけど、今は不要。

Quicklispインストール

Quicklispをダウンロード。
curlが必要。

$ cd ~/opt
$ curl http://beta.quicklisp.org/quicklisp.lisp >quicklisp.lisp

Quicklispをインストール。

$ cd ccl
$ ./armcl
? (load "quicklisp.lisp")
? (quicklisp-quickstart:install)

初期化ファイル .ccl-init.lispで起動時にQuicklispを読み込むようにする。

? (ql:add-to-init-file)

これで完了。

Slimeインストール

Emacsからslimeを使えるようにする。

$ ./armcl

起動するまで少々時間がかかる。
(Quicklispのパッケージの依存関係でも調べているのだろうか?)

? (ql:quickload "quicklisp-slime-helper")

こんなパッケージがあったのかー!知らなかった。
ロードが完了したら、emacsの初期化ファイルに以下を書く。

(load (expand-file-name "~/quicklisp/slime-helper.el"))
(setq inferior-lisp-program "/home/pi/opt/ccl/armcl")
  → piユーザではない場合は変更。
(setq slime-net-coding-system 'utf-8-unix) ; ← 2013/4/7 追加

emacsを起動して、

M-x slime

でreplが起動する。
自分の環境では起動するまで50秒弱かかった。

swankサーバ

Emacsからいちいちslimeコマンドを実行して、cclを起動するよりも、
swankサーバを起動しておき、Emacsから接続する方が便利。
ccl-swank.lispを次の内容で作成しておく。

(ql:quickload :swank)
(swank:create-server :port 4005 :dont-close t)

./armcl -l ccl-swank.lisp
  → ccl-swank.lispの置き場所に応じてパスを変更。

しばらく待つと、サーバーが起動するので、
別ターミナルでemacsを起動する。

M-x slime-connect

ホストとポート番号を聞いてくる。
デフォルトのlocalhost、4005番でOK。
すぐにreplが起動する。

hunchentoot

replから
(ql:quickload :hunchentoot)
ロードが完了したら、サーバーを起動。
(hunchentoot:start (make-instance 'hunchentoot:easy-acceptor :port 4242))
起動したら、ブラウザより http://localhost:4242 を開く。
Welcome画面が表示される。

以上の手順で、hunchentootが使えるようになった。
何を作ろうかなー?
ブラウザ経由でRaspberry PiのIOを使うようなものが面白いかな。