CakePHP 始めた [PHP]
ちょっと Web アプリで作りたいものを思いついて CakePHP [1] (Ruby on Rails の考えかたに影響を受けたらしい PHP 用のフレームワーク)を始めてみたんだけどかなり楽しい。今まで漠然とフレームワークというものには自分は馴染めないんじゃないかと思ってたんだけどそうでもなかった。大体以下のような要素が好感に結びついていると思われる。
1. アップロードするだけですぐに使えた
CakePHP はパッケージを解凍してその辺の PHP と DB をサポートしているレンタルサーバにアップロードすればすぐ使える(DB 設定のみ必要)。これはフレームワークというのから連想されるのとはまったく違う手軽さだったので大変感動した。これに匹敵する手軽さのフレームワークって他にあるのだろうか。
2. 目的をもって使っている
フレームワークというのはそれ自体で遊ぶことを考えると遊びどころないものなのかもしれないと思うのだけど、今回はこういうの作りたいというのが先にあってそれから手段として CakePHP を選んだ。目的がフレームワークの使用ではないというのがよい出会い感に結びついている気がする。
3. 私が PHP の書き方にこだわりが無い
これが OCaml だったら10行書くのにもそれがベストな書き方かどうかとか、フレームワークに強制される書き方とのギャップにしばし悩んだりしそうなんだけど、PHP に関しては特に自分の中にこだわりが無いというのが逆によい方向に作用しているのではないかと思った。フレームワーク嫌いの人は自分のこだわりが薄い言語のフレームワークを選ぶとむしろよいのではないか。
ところで CakePHP 本というのがあるのかどうか探してみたのだけど専用の本というのはなかった。PHP フレームワークをたくさん取り上げる中に CakePHP のことも書いてあるというのはあったけど、本屋でぱらぱらめくった限りでは特に濃い感じではなかったので購入はしなかった。英語の本でも特に CakePHP 本っていうのはまだ出てないみたいだ。
EOPL 第3章の Exercise 3.25 [Lisp]
前回のレキシカル変数に名前は不要というアプローチを推し進めて環境から完全に名前を消してしまう。これにより env 系の関数は非常に単純になった。プログラムの字面の解析を事前に手厚くしておく分だけ実際の実行が単純になるということかな。
前回の練習問題では lexical-address 関数が変数を lexvar に変換できなかった場合(つまり自由変数の場合)も考慮しておいたのだけど env 系関数から変数名が消えたことによりこれが意味をなさなくなった。あわせて init-env から組み込みのバインディグを削除した。
ここでは束縛されない変数が現れた場合は実行時(eval 時)のエラーにしたけどプログラム解析の段階でエラーにすることもできると思う(lexical-address 内の get-address 関数の4行目)。
EOPL 第3章の Exercise 3.23 と 3.24 [Lisp]
Exercise 3.23 は「レキシカル変数について名前は重要ではなく、レベルと位置で識別できる」という第1章で学んだことをいま作っている処理系に適用して lexical-address 関数のこの言語版を作る。このためにヴァリアント型に lexvar-exp を追加した。3.24 は apply-env を改造して変数が確かに lexical-address で予測された位置に現れるということの答えあわせができるようにする。
EOPL 第3章の Exercise 3.19 から 3.22: proc の追加 [Lisp]
EOPL の続きでファーストクラスの関数の追加。プリミティブの適用とユーザ定義関数の適用が全然違う構文になるので気持ち悪いけど…
練習問題 3.20 は引数の数のチェック機能の追加。練習問題 3.21 と 3.22 は letrec を導入しなくてもここまでで作った言語で再帰が書けるよって話。このテクニックは面白いな。型付き言語だとどういう型にすればいいんだろう?
ちなみに私はいままで SLLGEN での文法定義と define-datatype による構文木のヴァリアント型定義は別個にしなければいけないと思っていて構文を追加するごとに2箇所(eval を入れて3箇所)に手を入れるのは面倒くさいと感じていたんだけど、実は sllgen:make-define-datatypes は define-datatype するところも自動でやってくれていたらしい。
入力値をソートするプログラムを Camlp4 で生成 [OCaml]
どう書くorgの問題の回答なのだけど今サイトが落ちてるみたいなのでこっちの記事にしてしまうことにしました。「『ユーザからの整数の入力を変数に入れてそれらを if だけでソートするプログラム』を生成するプログラムを書け」という問題です。既に投稿されていた shiro さんの Scheme のコードを参考にしつつ OCaml + Camlp4 3.9 で書きました。実は Camlp4 を使わないほうが楽に書けたのではないかという気も。
(*
#load "camlp4o.cma";;
#load "q_MLast.cmo";;
#load "pr_o.cmo";;
ocamlopt -pp 'camlp4o q_MLast.cmo' \
-I +camlp4 gramlib.cmxa camlp4.cmxa pa_o.cmx pr_o.cmx -o gensort gensort.ml
*)
let _loc = Token.dummy_loc;;
let var_of_int n = String.make 1 (char_of_int (n + 97));;
let vars n = Array.to_list (Array.init n var_of_int);;
let make_lid_list lids =
List.fold_right (fun x l -> <:expr< [$lid:x$ :: $l$] >>) lids <:expr< [] >>;;
let wrap_fun args e =
List.fold_right (fun x l -> <:expr< fun $lid:x$ -> $l$ >>) args e;;
let rec gencode sorted = function
| [] -> <:expr<
print_int_list $make_lid_list (List.rev sorted)$
>>
| u::us ->
let rec insert rs = function
| [] -> gencode (List.rev (u::rs)) us
| s::ss -> <:expr<
if $lid:s$ < $lid:u$ then
$(gencode (List.rev (u::rs) @ s::ss) us)$
else
$(insert (s::rs) ss)$
>>
in
insert [] sorted;;
let gensort n =
let vars = vars n in
let fmt = String.concat " " (Array.to_list (Array.make n "%d")) in
let e = gencode [] vars in
let f = wrap_fun vars e in
let s = <:str_item<
let print_int_list xs = do {
List.iter (fun x -> do {print_int x; print_string " "}) xs;
print_newline ()
}
in
Scanf.scanf $str:fmt$ $f$
>>
in
(!Pcaml.print_implem) [s, _loc];;
gensort (int_of_string Sys.argv.(1))
生成、コンパイル、実行の結果。
KURO-BOX% ocamlopt -pp 'camlp4o q_MLast.cmo' \ -I +camlp4 gramlib.cmxa camlp4.cmxa pa_o.cmx pr_o.cmx -o gensort gensort.ml KURO-BOX% for n in 1 2 3 4 5 6 7; do time ./gensort $n > a$n.ml; done ./gensort $n > a$n.ml 0.03s user 0.04s system 95% cpu 0.073 total ./gensort $n > a$n.ml 0.02s user 0.05s system 94% cpu 0.074 total ./gensort $n > a$n.ml 0.06s user 0.02s system 97% cpu 0.082 total ./gensort $n > a$n.ml 0.09s user 0.03s system 99% cpu 0.121 total ./gensort $n > a$n.ml 0.33s user 0.03s system 99% cpu 0.363 total ./gensort $n > a$n.ml 2.01s user 0.05s system 99% cpu 2.066 total ./gensort $n > a$n.ml 15.66s user 0.34s system 99% cpu 16.003 total KURO-BOX% for n in 1 2 3 4 5 6 7; do time ocamlc -o a$n a$n.ml; done ocamlc -o a$n a$n.ml 0.25s user 0.07s system 97% cpu 0.327 total ocamlc -o a$n a$n.ml 0.24s user 0.09s system 98% cpu 0.336 total ocamlc -o a$n a$n.ml 0.30s user 0.05s system 99% cpu 0.351 total ocamlc -o a$n a$n.ml 0.36s user 0.08s system 101% cpu 0.435 total ocamlc -o a$n a$n.ml 0.91s user 0.08s system 99% cpu 0.992 total ocamlc -o a$n a$n.ml 6.06s user 0.13s system 99% cpu 6.191 total ocamlc -o a$n a$n.ml 108.27s user 0.58s system 99% cpu 1:48.87 total KURO-BOX% ./a6 5 2 4 6 1 3 1 2 3 4 5 6
生成されるのはこんな感じのコード(値が3のとき)。
let _ =
let print_int_list xs =
List.iter (fun x -> print_int x; print_string " ") xs; print_newline ()
in
Scanf.scanf "%d %d %d"
(fun a b c ->
if a < b then
if b < c then print_int_list [a; b; c]
else if a < c then print_int_list [a; c; b]
else print_int_list [c; a; b]
else if a < c then print_int_list [b; a; c]
else if b < c then print_int_list [b; c; a]
else print_int_list [c; b; a])
F# + Silverlight で Hello World (2) [OCaml]
XAML で定義したキャンバス上の部品に F# 側からアクセスするには Canvas の FindName メソッドを使えばいいようだ。
というわけで XAML を以下のように変更する。Greeting という名前のテキストブロックを追加したほか、MouseLeftButtonDown イベントで Page_MouseLeftButtonDown メソッドが呼ばれるように指定した。
<Canvas
xmlns="http://schemas.microsoft.com/client/2007"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
MouseLeftButtonDown="Page_MouseLeftButtonDown"
x:Class="SilverTest.Page;assembly=SilverTest.dll"
>
<TextBlock x:Name="Greeting">Hello Silverlight!</TextBlock>
</Canvas>
F# のほうではイベントに呼応して FindName を使って TextBlock を探し出して内容を書き換える。
namespace SilverTest
open System;
open System.Windows;
open System.Windows.Controls;
open System.Windows.Documents;
open System.Windows.Ink;
open System.Windows.Input;
open System.Windows.Media;
open System.Windows.Media.Animation;
open System.Windows.Shapes;
type Page = class inherit Canvas
new() = {}
member x.Page_MouseLeftButtonDown(o : obj, e : MouseEventArgs) =
let canvas = o :?> Canvas in
let text = canvas.FindName("Greeting") :?> TextBlock in
text.Text <- "I was pushed!!"
end
EOPL 第3章の Exercise 3.16 から 3.18: let の追加 [Lisp]
EOPL の続き。今回は let 式を追加。Exercise では eq? 関数とリストを変数に展開する unpack 式を追加した。
gosh> (read-eval-print) let x = 1 in x -->1 let x = list(1,2,3) in unpack x y z = x in +(1,+(2,3)) -->6 let x = list(1,2,3) in let y = x in eq?(x,y) -->#t
F# + Silverlight で Hello World [OCaml]
とりあえず文字を表示するだけのものを作った。Silverlight は 1.1 Alpha Refresh が必要。
index.html を以下のように書く。Silverlight.js は SDK に含まれるものを置く。
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head>
<script type="text/javascript" src="Silverlight.js"></script>
<title>Hello Silverlight!</title>
</head>
<body>
<!-- ここに Silverlight コントロールが表示されます -->
<div id="SilverlightControlHost"></div>
<script type="text/javascript">
// Silverlight コントロールをロードします
function createSilverlight()
{
Silverlight.createObjectEx({
source: 'Page.xaml',
parentElement:document.getElementById("SilverlightControlHost"),
id:'SilverlightControl',
properties:{
width:'200',
height:'200',
background:'silver',
isWindowless:'false',
framerate:'24',
enableFramerateCounter:'false',
version:'1.0'
},
events:{
onError:null,
onLoad:null,
onResize:null
},
context:null
});
}
createSilverlight();
</script>
</body>
</html>
Page.xaml は事実上の空。マネージドコードを使うので x:Class 属性にクラス名と DLL の場所を指定する。Loaded 属性で指定したメソッドがロード時に呼ばれる。
<Canvas
xmlns="http://schemas.microsoft.com/client/2007"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Loaded="Page_Loaded"
x:Class="SilverTest.Page;assembly=SilverTest.dll"
>
</Canvas>
SilverTest.fs が F# のコード。Page_Loaded で TextBlock オブジェクトを作ってキャンバスに追加する。[1] などを参照した。
namespace SilverTest
open System;
open System.Windows;
open System.Windows.Controls;
open System.Windows.Documents;
open System.Windows.Ink;
open System.Windows.Input;
open System.Windows.Media;
open System.Windows.Media.Animation;
open System.Windows.Shapes;
type Page = class inherit Canvas
new() = {}
member x.Page_Loaded(o : obj, e : EventArgs) =
let canvas = o :?> Canvas in
let text = new TextBlock() in
text.Text <- "Hello Silverlight!!";
text.SetValue(Canvas.TopProperty, 0);
text.SetValue(Canvas.LeftProperty, 0);
canvas.Children.Add(text);
end
コンパイルオプション。[2] に書いてあったのをほぼそのまま使った。
fsc -r System.SilverLight.dll -r agclr.dll -r Microsoft.Scripting.Vestigial.dll -r System.dll -r Microsoft.Scripting.Silverlight.dll -r Microsoft.Scripting.dll --clr-root "C:\Program Files\Microsoft Silverlight" --no-framework --no-mllib --static-link fslib -a SilverTest.fs
XAML で定義したキャンバス上のオブジェクトを F# 側から触る方法がまだ分からなくて、何も出来ていないようなものだ。C# のサンプルなんかでは何もしなくても名前で指定できてるっぽいんだけど。あと F# のクラス構文もまだ全然わかってない。
[1] http://www.strangelights.com/blog/archive/2007/05/25/1584.aspx
[2] http://www.strangelights.com/blog/archive/2007/05/28/1585.aspx
Erlang の文法と van Wijngaarden form [Erlang]
形式言語を記述するための記法としては Backus-Naur Form とそれを適当に改変した方言が圧倒的に使われていると思いますが、その他に van Wijngaarden form というのがあるそうです。例を挙げると以下の上が BNF で 、下が同じ文法を van Wijngaarden form で書いたもの。
<additive> ::= <multitive> + <additive> | <multitive> <multitive> ::= <primary> * <multitive> | <primary> <primary> ::= ( <additive> ) | <decimal>
additive: multitive, + symbol, additive; multitive. multitive: primary, * symbol, multitive; primary. primary: ( symbol, additive, ) symbol; decimal.
すなわち、
1. 連続するものはカンマでつないで表現する
2. 選択肢はセミコロンで区切って表現する
3. 最後はピリオド
このカンマ、セミコロン、ピリオドの使い方は何かを思い起こさせるなーと思ったら Erlang だった。それで Erlang の文法が van Wijngaarden form に由来するのだという証言がないかどうかちょっと検索してみたけど見つからず。
しかし「いつも使い分けが分からなくなる」「ピリオドのせいで行のコピー&ペーストなどの編集が面倒」など Erlang の文法で特に評判の悪い部分が実は由緒ある(?)文法記法と同じだと思えばきっとそんなに嫌いではなくなるのではないでしょうか。そうでもないか。