2011年8月28日日曜日

Scheme修行12章



学園祭の準備をしつつ12章を読みました。学園祭が無事終了したのでブログのエントリをあげます。

11章では必要があれば一つ前の要素や今までの加算の結果や逆順のリストなど付加的な引数を渡す、第11の戒律を学びました。

JavaScriptのreduce - MDNと似た感じの印象を受けました。

12章ではletrecについて。

再帰する時に変化しない引数をletrecを使って除く方法、第12の戒律を学びます。

この章の名前は「避難しましょう」です。letrecのもう1つの使い方として、補助関数を守るための第13の戒律が出てきます。




メモなど




  • multiremberのYコンビネータを使った定義では一番外側のlambdaでaが束縛されるのでYコンビネータに渡す関数の中でaを使う事が出来る。

  • p18の動かないmrの定義


    • mrの中のaは束縛されていない自由変数

    • Schemeは静的スコープなのでmrが定義された時にaが値に束縛されてないとunbound variableとエラーが出て動かない。

    • mrを呼び出しているmultiremberの中の変数aはmrの定義時にはスコープの外、mrからはaが見えていない。

    • 試しにElispで書いたら動いた。Elispは動的スコープなので呼び出し元の環境の変数aを参照するため動く。

(defun mr (lat)
(cond ((null lat) '())
((eq a (car lat)) (mr (cdr lat)))
(t (cons (car lat) (mr (cdr lat))))))

(defun multirember (a lat)
(mr lat))

(multirember 'pie '(apple custard pie linzer pie torte))




  • p19にてα変換、α同値の話が出てくる。

  • p20 「再起関数」typo発見

  • p20 「(letrec ...)の名前づけ部分で定義された関数は囲まれている全ての(lambda ...)式の全ての引数を知っています。」


    • (letrec ( (mr ...) ) mr)はmrという名前の関数を定義して、その再帰関数を返している。

    • letrec中のmrは外側のlambdaの引数aを知っている。

  • letrecを使ったmultirember


    • mr pieを定義してlatに用いたように見える

    • p21下線のついたdefineは実際には存在しないけれどそのように想像することで理解の助けになる

    • mr pieはdefineを使って定義した関数と違って外側からは見えない!

  • 第12の戒律「再帰を適用している間に変化せぬ引数を除くには(letrec ...)を用いるべし。」

  • p23~p26でletrecを使ってmultirember-fを定義している。letrecの使い方は同じ。関数を定義して返す。

  • member?やunionなどを第12の戒律に従い書き直し。


    • member?の中のyes?で引数の名前がlなのはlatと被らないように?それとも短い名前がよかったから?

  • 関数を守る


    • unionの中のUは、unionが知っている事はすべて知っている。

    • unionの中にmember?の定義は出てこない

    • unionの動作はmember?に依存してる。member?の引数の順番が変わったら動かなくなってしまう。

    • letrecはかっこで囲んだ関数定義を複数おける。(condの条件みたいに)

    • そこで、unionの内側のletrecでmember?を定義する

  • 第13の戒律「関数を隠し、守るには、(letrec ...)を用いるべし。」


    • 補助関数はその関数にとって特別な値に使う。だから補助関数の定義が変わって変な値を返さないようにその場に隠す。

感想


letrecと(define (hoge) (define (fuga) ...) ...)

SICPでは補助関数はdefineの中でdefineを書いてた気がします。

defineの中にdefineだとどうなるんだろう、気になったので調べてみると

letrec - karetta.jp

letrecを使うか、defineの中にdefineを書くかは好みの問題です。

本当に好みの問題なのか気になったのでR5RSを読んでみると

Revised(5) Report on the Algorithmic Language Scheme

内部での定義を含む<ボディ>は、完全に等価なletrec式に必ず変換できる。例えば上記のlet式は次の式に等価である。

だそうで、やっぱり好みの問題らしい。

印象に残った部分

p28の

Q.

そのとおり。AはUとまったく同じ名前です。
どんな名前でもかまいませんよね。

A.

かまいませんが、定義を楽しみたい人にとって名前の選び方は大切です。

と書いてあったのがちょっと印象的。やっぱり関数の名前付けは大事。

Aじゃよく分からなくてもUだったらUnionのUだなって分かるので。

テスト

今まで

$ gosh test11.scm

とやってたのを

$ for i in `ls test*.scm`; do gosh $i; done

とするようにした。今回11.scmの中身も書き換えたのでいちいちgosh test11.scm、gosh test12.scmと2回やるのが面倒だったので。

シェルスクリプトも覚えないと orz

少し残った疑問と次章への期待

関数をどこらへんまで守るべきなんだろうか。

他にもmember?を使う関数があったらその関数も内部で同じmember?を持つので無駄な気もするんだけど。

member?が引数を決まった順序で取るという仮定が崩れないなら使ってもいいのかな…

とりあえず



  • 関数が他の関数の定義に依存すると、依存している関数の定義を変えたとき動かなくなってしまう

  • 動かなくなると困る関数はletrecで守る。隠す。

というのをしっかり頭に置きながら残りの章を読んで行きたいと思います。

どうやら次章でついに継続が出て来る! call/cc! call/cc!

楽しみです :)




2011年8月25日木曜日

Scheme修行11章



11章を読んでいたのでメモと感想をまとめてみます。


メモ




  • Scheme手習いの続きなので11から始まる。

  • 究極のλを知っていますか?

  • two-in-a-row-b?は2つの引数が変わるのに、質問は1つの引数についてのみ

  • p10「一方の引数は他方の引数について関数に何かを伝えます」


    • このトリックは面白い

    • two-in-a-row-bのprecedingではlatの引数の前の要素を

    • sum-of-prefixes-bのsonssfはこれまでの全ての数の合計を

    • scramble-bのrev-preは自分より前の部分の逆を



  • 第11の戒律「ある関数が、その関数に対する他の引数がいかなるものか知る必要があるときは、付加的な引数を用いるべし。」

  • 出てきてる用語


    • parsleyはパセリ

    • sardinesはイワシ

    • sonssfは「sum of numbers seen so far.(それまで見てきた数の合計)」の略

    • scrambleのニュアンスがちょっと分からない

    • rev-preはreversed prefix



  • 前章で定義してあったone?やpickなどの手続きを使っているので、11.scmの先頭に定義した


    • atom?等、他の章でも使うものは共通のファイルに抜き出していこうと思う。



  • 「関数の手がかりは、いつだってその名前です。」


    • いい名前は理解を助けてくれますね。



  • 食事の回数、3回


    • p13 「覚えているならアイスクリームを食べましょう」

    • p15 「スナックを食べる前に」

    • p15 「お茶の時間です。」




感想


「はじめに」によると「食べ物がちょっとした気晴らしになってこの本を一度にたくさん読まないで済むことを願っている」らしい。


でも面白いから読み始めると1章、一気に読んでしまいますね。


読んでから少し時間が経ってしまったので理解しているか確かめるためにthree-in-a-row?を定義してみた。



(define three-in-a-row-b?
(lambda (preceding1 preceding2 lat)
(cond ((null? lat) #f)
(else (or (and (eq? preceding1 preceding2)
(eq? preceding2 (car lat)))
(three-in-a-row-b? preceding2 (car lat) (cdr lat)))))))

(define three-in-a-row?
(lambda (lat)
(cond ((null? lat) #f)
((null? (cdr lat)) #f)
(else (three-in-a-row-b? (car lat) (car (cdr lat)) (cdr (cdr lat)))))))


で、n-in-a-row?を定義したくなったので色々といじっていたらいつの間にかYコンビネータを書いたり



(define Y
(lambda (f)
((lambda (x) (x x))
(lambda (x) (f (lambda (y) ((x x) y)))))))

(define L
(lambda (length)
(lambda (l)
(cond ((null? l) 0)
(else (+ 1 (length (cdr l))))))))

(define T
(lambda (take)
(lambda (nl)
(cond ((= 0 (car nl)) '())
(else (cons (car (car (cdr nl)))
(take (cons (- (car nl) 1)
(cons (cdr (car (cdr nl)))
'())))))))))
(define length (Y L))
(define take (Y T))

(define n-in-a-row?
(lambda (n)
(Y (lambda (n-in-a-row?)
(lambda (lat)
(cond ((> n (length lat)) #f)
(else (or ((Y ((lambda (a)
(lambda (every)
(lambda (lat)
(cond ((null? lat) #t)
((eq? a (car lat))
(every (cdr lat)))
(else #f)))))
(car lat)))
(take (cons n (cons lat '()))))
(n-in-a-row? (cdr lat))))))))))


それを無名にしてみたり



(define n-in-a-row?
(lambda (n)
((lambda (f)
((lambda (x) (x x))
(lambda (x) (f (lambda (y) ((x x) y))))))
(lambda (n-in-a-row?)
(lambda (lat)
(cond ((> n (((lambda (f)
((lambda (x) (x x))
(lambda (x) (f (lambda (y) ((x x) y))))))
(lambda (length)
(lambda (l)
(cond ((null? l) 0)
(else (+ 1 (length (cdr l)))))))) lat)) #f)
(else
(or (((lambda (f)
((lambda (x) (x x))
(lambda (x) (f (lambda (y) ((x x) y))))))
((lambda (a)
(lambda (every)
(lambda (lat)
(cond ((null? lat) #t)
((eq? a (car lat)) (every (cdr lat)))
(else #f)))))
(car lat)))
(((lambda (f)
((lambda (x) (x x))
(lambda (x) (f (lambda (y) ((x x) y))))))
(lambda (take)
(lambda (nl)
(cond ((= 0 (car nl)) '())
(else (cons (car (car (cdr nl)))
(take (cons (- (car nl) 1)
(cons (cdr (car (cdr nl)))
'())))))))))
(cons n (cons lat '()))))
(n-in-a-row? (cdr lat))))))))))


なんかこの章の理解を確かめるというより究極のlambda復習してしまった orz





2011年8月22日月曜日

Scheme修行の11章を読む前に



Scheme手習いを読み終わったのでScheme修行を読みます。


本文の前に




  • 訳者前書き

  • 序文

  • はじめに


があるのでまずは気になったところのメモと感想など書きます。


訳者前書き


メモ



  • Scheme手習いと同じ著者による続編

  • 2冊合わせてSchemeの入門書として完結


    • なのでScheme手習いの続き、11章から始まっている



  • Scheme手習いと同じく質問と答えのペア

  • 前作は「再帰的」な考え方、今回は継続と代入

  • 他の言語にも継続に似た機能はある


    • Lispの例外(catch throw)やCのsetjump, longjump

    • 大域的な脱出手段なので後から使えない(のかな?)

    • Schemeの継続はいつでも使用することは可能



  • Scheme手習い・Scheme修行ではSchemeの制御構造については継続をのぞいては触れられていない


    • 末尾再帰最適化の話とか


      • Schemeは静的束縛なのでそれが実現出来るらしい

      • 動的な束縛をする言語では実現出来ない

      • 似たような言語だからといってLispで同じことをやるとスタックが溢れる





  • letccを実現するためにletccを使っているので本書で作成しているインタプリタはSchemeでしか実現出来ない

  • 継続渡しスタイルについて調べてみるのも面白い


感想

スタックの話でもあったけどSchemeはLispの方言とは言うがLispとは別物のよう。


Lispによって変数のスコープも違えば言語で規定されてる機能も全然違いそう。


継続渡しスタイルについては後で継続渡しスタイル - karetta.jpを読もうと思う。


ということはSchemeじゃないLispにはSchemeにない機能もあるに違いないので読み終わったら取り組む。


実はPractical CommonLisp読んでる途中でやめちゃいましたので。


序文


メモ



  • 「もし誰かに魚をあげたら、一日食べることができる。もし誰かに釣りを教えたら、一生食べることができる。」

  • Lispは元々「LISt Processor」、リスト処理

  • Lispはリストだけでなく計算を行う関数を持っている。リストはLispの心臓、関数は魂。

  • 生きるためには食べ物以外のものも必要。釣りを習いましょう!


感想

リストが心臓で関数が魂ってなんかアツい!


確かにLispにはどっちも欠かせない気がする。


リストが心臓で関数が魂なら、マクロは一体なんだろう?


序文の最初に出て来る言葉は深い。


ググってみたけど中国のことわざ?元ネタが分からないです orz





はじめに


メモ



  • 「この本の目的は、読者に計算の性質について考えることを教えることにある。」

  • プログラミング言語は、計算の性質を伝える最も良い方法、数学と違い直接体験出来る

  • プログラミングの実用的な世界への入門書ではないが、計算の性質を理解する出発点

  • ガイドライン


    • 急いで読んではだめ。5回未満で読み切ろうとしないこと。(ちなみにScheme手習いには2回未満で読み切ろうとしないこと、と書いてる)

    • 飛ばして後ろから読んではだめ。少しずつ難しくなっていくので完全に理解してから進む。

    • 「読みながら例を試してほしい」

    • 「この本では形式的な定義はしない。読者が自分の定義を形式化し、覚えて理解するほうがよいと信じているからである」

    • しかし戒律はその先を読む前に知って理解しておくこと。

    • プログラミングのこつはデータおよび処理のパターンを認識すること。




感想

最後に「次のページで読者を待っている挑戦を楽しんでほしい。」と書いていた。なので、Scheme修行も楽しみながら読むぞ!


ガイドラインに書かれていたように、本にちりばめられたヒントから自分の定義を形式化し、覚え、理解したい。


ちりばめられたヒントを拾うためにも5回ぐらい読まないと気づかない点があるんだと思う。


計算の性質について考えれば、一生プログラマで食べていくこと、出来るかな?





2011年8月19日金曜日

PHP5技術者認定初級試験に合格しました。



授業のカリキュラムの1つとしてPHPを勉強しています。


今日初級試験 - PHP技術者認定試験を受けてきました。


まだ新しい検定です。Twitterもやってます→@フォローしました。


プロメトリックの試験センターで受けられます。沖縄だと産業支援センターが試験会場として選べます。


一応合格しましたが72点、合格ラインぎりぎり orz


レポートはこんな感じです。


f:id:h6n:20110819125334j:image


0%だったのが




  • 日付と時刻の取り扱い

  • セキュリティ

  • 出力バッファ

  • 定数・予約語


これは酷い。これからここを勉強しなければ。


今回受けた初級試験の出題範囲は



初めてのPHP5

初めてのPHP5







のカバーしている範囲から万遍なく出ます。詳しくは公式サイトを見てください。


また、9月からは上級試験が開始されるようです。上級試験の内容は



プログラミングPHP 第2版

プログラミングPHP 第2版







から出るようなので今から勉強して卒業までに取得できたら嬉しいな。


受けてみての感想


万遍無く出るので普段使わない機能まで勉強出来ました。普通に使っていれば分かりそうな問題もあればちょっと細かい問題もありました。


あと、レポートで間違ったところがはっきり分かるので嬉しいですね。理解が足りてないところを重点的に勉強出来ます。


合格はしたけどまだまだ仕事で使うには能力が足りてない。趣味でSchemeしつつ、noviceからexpertなPHPerになるべく、プログラミングPHPを読んでいきます。


9月の試験が楽しみ!





2011年8月18日木曜日

Yコンビネータを理解したい



Scheme手習いの9章にYコンビネータが出てきます。


Y combinator - /var/log/messages


を読んで、もう一度しっかり取り組んでみようかと思いました。


前回読んだときの感想で最後に「すっきり」と書いておきながら再度9章読むとやっぱり理解出来てなかったかも。


頑張って「λ計算入門」でググって基礎文法最速マスターを読んだり、どこかの大学の講義のpdfな資料を読んだり、Yコンビネータでググって資料を読んだり。(本はScheme手習い以外読んでないです*^q^*


少しだけ分かった気がするのでエントリにまとめておきます。


Yに渡す関数


リストの長さを求める関数、とりあえずFとでも名付けましょう。



(define F
(lambda (length)
(lambda (l)
(cond ((null? l) 0)
(else (+ 1 (length (cdr l))))))))


Fは長さを計算する関数lengthを取り関数を返す。


listを取って空なら0を、それ以外の場合lのcdrの長さをlengthで求めそれに1を加えて返す関数。


Yコンビネータ



(define Y
(lambda (le)
((lambda (f) (f f))
(lambda (f)
(le (lambda (x) ((f f) x)))))))


中身の2つの関数、別々に見てみる。


最初の関数


(lambda (f) (f f))


関数fを引数に取り、fにfを適用する。(この時点でちょっと???な感じww)


2番目の関数B


(lambda (f)
(le (lambda (x) ((f f) x))))


引数で直接(le (f f))という風に渡すと、先に引数を評価してからleを呼び出すので、leを呼び出す前に(f f)の部分で延々と再帰します。


なのでlambdaで包んで評価を遅らせてますね(p173)


FにYを適用するとどうなるのか


とりあえずScheme手習いで出て来るYコンビネータをFに適用する



(Y F)


Yの定義のlambdaに置き換え。



((lambda (le)
((lambda (f) (f f))
(lambda (f)
(le (lambda (x) ((f f) x))))))
F)


leの部分をFで置き換えてこんな感じになる。



((lambda (f) (f f))
(lambda (f)
(F (lambda (x) ((f f) x)))))


fの部分を置き換えて



((lambda (f)
(F (lambda (x) ((f f) x))))
(lambda (f)
(F (lambda (x) ((f f) x)))))


こうなる。


よく見るYコンビネータの中身と同じになりましたね。


で、こうなると、(lambda (f) ...)で取っているのは自分自身


Fに渡す無名関数



(lambda (x) ((f f) x))


の中で使われてるfは



(lambda (f)
(F (lambda (x) ((f f) x))))


に束縛されてるのかな。


無名関数にFを適用する

さて、帰って来る(F (lambda (x) ((f f) x)))のFを置き換えてみると



((lambda (length)
(lambda (l)
(cond ((null? l) 0)
(else (+ 1 (length (cdr l)))))))
(lambda (x) ((f f) x)))


lengthを引数で置き換えて



(lambda (l)
(cond ((null? l) 0)
(else (+ 1 ((lambda (x) ((f f) x)) (cdr l))))))


こんな関数が帰って来る、と。これがlengthか。


その関数に'()を与えると、0を。そうでない場合に+1して



((lambda (x) ((f f) x)) (cdr l))


が呼び出されています。


(f f)が何をしてるか

このfには



(lambda (f)
(F (lambda (x) ((f f) x))))


が入っています。なのでこれにfを与える、つまり



((lambda (f)
(F (lambda (x) ((f f) x))))
(lambda (f)
(F (lambda (x) ((f f) x)))))


となる。


で、これさっき見たよね。


(f f)を呼び出すだけで再帰が出来とる!!w


YじゃなくてZコンビネータらしい


(lambda (x) ((f f) x))


でlambdaでくるんでるのは(f f)が引数の方が先に評価されてしまうから。評価順序云々が絡んでるみたいです。先行評価。


で、実はλで遅延させてるのはZコンビネータらしい。


普通のYコンビネータはこう。



λf.(λx.f(xx))(λx.f(xx))

Zはこう。



λf.(λx.f(λy.xxy))(λx.f(λy.xxy))

Zの一部をη変換するとYと同じになる、という理解。


Yコンビネータの話



Y = λf.(λx.f(xx))(λx.f(xx))

MにYを適用してみると



YM = λf.(λx.f(xx))(λx.f(xx))M
= (λx.M(xx))(λx.M(xx))
= M(λx.M(xx)(λx.M(xx)))

最終的にこんな形に。3行目の引数が2行目と同じになるので


YM=M(YM)


Zだと



Z = λf.(λx.f(λy.xxy))(λx.f(λy.xxy))
ZM = (λf.(λx.f(λy.xxy))(λx.f(λy.xxy)))M
= (λx.M(λy.xxy))(λx.M(λy.xxy))
= M(λy.(λx.M(λy.xxy))(λx.M(λy.xxy))y)

Mの引数で渡してるのはλ、ここで1回評価を遅らせてる感じなのだろうか


最後の形の引数をη変換すると



(λx.M(λy.xxy))(λx.M(λy.xxy))

となって、ZMを簡約してる途中で出てきたのと同じ形になる


つまり、M(ZM) = ZM


ってことなのかな


(Y Y)はどうなるの


YFするとF(YF)が帰って来る。ここでFの場合はYFをlengthとして受け取った後に、(lambda (l) …)な関数を戻しているのでそこで計算が止まる。


YYするとY(YY)が帰って来る。Y(YY)はYYを返す。でYYはY(YY)を返す。でYYは…と無限ループする。


という理解でいいのかな。





2011年8月13日土曜日

「ランダム文字列」をGaucheで解いてみる



お題:ランダム文字列 - No Programming, No Lifeを書いてみる。


すっきり。#[\w]は文字集合、\wは単語を構成する文字の集合でa-zA-Z_。#[a-zA-Z0-9_]でもいいかな。


char-set->stringで文字集合を文字列に変換するためにsrfi-14


文字列をshuffleでシャッフルするのにgauche.sequence


16文字抜き打すのにsrfi-13のstring-takeを使っています。


追記


さっき



(use gauche.sequence)
(use srfi-13)
(use srfi-14)
(string-take (shuffle (char-set->string #[a-zA-Z0-9_])) 16)


こんなの書いてましたが誤りです。これだと同じ文字が2連続しない。ランダムではない。恥ずかしい。


これでどうだ!



(use gauche.sequence)
(use srfi-14)
(use srfi-42)
(string-ec (: i 16) (~ (shuffle (char-set->string #[a-zA-Z0-9_])) 0))


また追記


実行時間をはかろうとしてtimeしたら



gosh> (time (length '(1 2 3)))
ERROR: failed to link /usr/local/Cellar/gauche/0.9.2/lib/gauche-0.9/0.9.2/i386-apple-darwin11.0.1/gauche--auxsys.so dynamically: dlopen(/usr/local/Cellar/gauche/0.9.2/lib/gauche-0.9/0.9.2/i386-apple-darwin11.0.1/gauche--auxsys.so, 10): Symbol not found: _environ

Referenced from: /usr/local/Cellar/gauche/0.9.2/lib/gauche-0.9/0.9.2/i386-apple-darwin11.0.1/gauche--auxsys.so
Expected in: flat namespace
in /usr/local/Cellar/gauche/0.9.2/lib/gauche-0.9/0.9.2/i386-apple-darwin11.0.1/gauche--auxsys.so
Stack Trace:
_______________________________________
0 (sys-times)
[unknown location]

こんな表示が。


後でググろう…


さっきのだと遅いかな、と思って書き直してみた



実行時間をはかる。

前のをちょっと変えたのをa.scmと今のをb.scmに書いて実行する


前の

a.scm



(use gauche.sequence)
(use srfi-14)
(use srfi-42)
(dotimes (n 1000)
(let ((src (char-set->string #[a-zA-Z0-9_])))
(string-ec (: i 16) (~ (shuffle src) 0))))



$ time gosh a.scm

real 0m1.475s
user 0m1.463s
sys 0m0.010s

今の

b.scm



(use srfi-14)
(use srfi-27)
(use srfi-42)
(dotimes (n 1000)
(let* ((src (char-set->string #[a-zA-Z0-9_]))
(src-len (string-length src)))
(string-ec (: i 16) (~ src (random-integer src-len)))))



$ time gosh b.scm

real 0m0.105s
user 0m0.098s
sys 0m0.006s

もっといい方法があるに違いない。





Hello World



あまりにも内容がない日記で申し訳ないのですが。


homebrewでnode.js入れてたのに何も遊んでないのでとりあえずHello Worldぐらいは出そうと思った。


公式サイトnode.jsの例だとlistenのポート番号に1337を指定してたけど、それだと


/etc/services



menandmice-dns 1337/udp # menandmice DNS
menandmice-dns 1337/tcp # menandmice DNS

と被ってしまうので8124に変更。



var http = require('http');
http.createServer(function (req, res) {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end('Hello World\n');
}).listen(8124, "127.0.0.1");
console.log('Server running at http://127.0.0.1:8124/');


http://127.0.0.1:8124/にアクセスしてHello Worldが表示される事を確認。


続いてecho serverを書く。



var net = require('net');

var server = net.createServer(function (socket) {
socket.write("Echo server\r\n");
socket.pipe(socket);
});

server.listen(8124, "127.0.0.1");



$ telnet localhost 8124

で確認、何か打って帰って来るのを確認。Ctrl + ]してqで終了。


とりあえず今日はここまで。





「文字列を先頭から見て同じところまで除去」をGaucheで解いてみた



お題:文字列を先頭から見て同じところまで除去 - No Programming, No Life

をGaucheで解いてみた。多分0.9じゃないと動かないです。



つぶやける長さになった!



学校卒業するまでの間はSchemeいっぱい書いて生きたい。

追記


あまりにも説明なさ過ぎな気がしたのでちょっとだけ説明も書いてみる。

後述するstring-prefix-lengthっていう便利な関数を使うため(use srfi-13)でSchemeのライブラリsrfi-13を読み込む。

(define (q . los) ~)のように書くとqに渡された引数が全て入ったリストがlosに束縛される。

qの中身を内側から見て行く。

srfi-13に用意されているstring-prefix-lengthを使うと2つの文字列の先頭から見て同じとこまでの長さが得られる。

(map (^s (string-prefix-length (first los) s)) los)


(^s ~)は(lambda (s) ~)のシンタックスシュガー、Gaucheの機能。

mapを使ってlosの全ての文字列sとlosの最初の文字列、2つの文字列の「先頭から見て同じとこまでの長さ」のリストを得る。

(apply min ~)でもっとも短い「先頭から見て同じとこまでの長さ」を取り出す。

そしてstring-dropでlosの全ての文字列sから、もっとも短い「先頭から見て同じとこまでの長さ」の分の文字を取り除く。

そんな流れです。

自分の理解を助けるためにも、もう一度さっくりまとめると



  • 2つの文字列の「先頭から見て同じとこまでの長さ」を返す便利な関数、string-prefix-lengthがsrfi-13で定義されてるのでそれを使う。

  • 関数に渡された全ての引数(文字列)をリストとして受け取る

  • 全ての文字列と最初に渡された文字列との「先頭から見て同じとこまでの長さ」を求める

  • 一番短い「先頭から見て同じとこまでの長さ」まで文字を取り除いた文字列を返す。

以上です。まじめに書こうとすると日本語難しい。

追記


何も考えず別解。



引数の中に空文字列か、先頭の1文字が他のと同じでない文字列があったら引数をそのまま返す。

それ以外の場合は引数の文字列を先頭から1文字取り除いて再帰

再帰! 再帰!




2011年8月12日金曜日

Scheme修行を読む。



Scheme手習いについて


Scheme手習いを読み終わりました。


Scheme手習い







本読んで内容を書いてhanachin/TheLittleSchemer ? GitHubにアップしてブログを書いてid:yamanetoshiさんに読んだエントリ投入のお知らせを書いて、疑問点等補足してもらって…という感じで読み進めました。

エントリあげる間隔はちょっとゆっくり目でしたが orz

ひとまず一冊読み終える事が出来て嬉しいです。

Scheme手習いの冒頭には2度以下で読むなと書いてあったので今度は同級生の方ともう一度読んでみようかと思ってます。

Scheme修行について


続編のScheme修行も購入しました。


Scheme修行







以前から手元にあって、手習いを読み終わったら読もうと思ってわくわくしていた本です。

手習いを読み終わった翌日、もう我慢出来なくなってしまって早速読書用のリポジトリhanachin/TheSeasonedSchemer ? GitHubを建ててマクドナルドに居座り一気に1章読んでしまいましたw

前回の書き方

前回は質問に対応したテストを読みながら書いていって、その質問の答えを定義して、テストが通るか確認して、というTDD的な流れで進めました。

テストケースのファイルを章ごとに1.scm、2.scm、3.scm...と作っていって、テスト用のマクロをtest-util.scmで少しだけ定義してテストケース冒頭で読み込み、本に出て来る関数の定義は全部func.scmの1ファイルに書いて、という感じの構成にしてみましたが最終的にfunc.scmが985行になりました。

全部1つに定義しちゃうと1章ごとにやった内容を確認しづらいし区切りがつけづらいかな、と思ったり。

あとコミットメッセージも謎の英語でぱっと見分からなかったような orz

今回はどうしよう

テストケースを書いてから答えを書く姿勢はそのままで行こうと思います。

テストケースになりそうな質問を本文から全て拾ってから答えを考え読み進めるようにします。

ファイルの構成は、前回func.scmが大きくなったのをふまえ、それぞれの章で使う関数の定義や質問の答えを11.scm、12.scm、13.scm...という風に1章1ファイルで書いていこうかと。

よく重複して定義してしまう関数は別途切り出したり、前章で定義した関数を使う際はloadで前章を読み込もうかと。

テストケースはtest11.scm、test12.scm、test13.scm...のようにtestを頭につけて1章1ファイルずつ作っていきます。

加えてnotes.orgにメモを取って、それもgitで管理する事にします。

後、コミットメッセージを日本語でちゃんと書くようにしてみます。

目標


前回、1章読む間隔が結構あいてしまったので1週間に1章は読むようにして、3ヶ月以内に読了していけるように頑張りたいです。

Scheme手習いだと2回以下で読み切るな、だったのがScheme修行だと5回以下で読み切るな、となってるので前回以上に読み込まなければならないですね…

楽しんで読めると嬉しいな。1章読んだエントリは後ほどあげます。




2011年8月9日火曜日

Scheme手習い Chapter 10



ついに10章まで来てしまった。この章で最後。手習いを終えたら修行が待っている。


いつも通り読みながらの気づき等


読みながらのメモ




  • エントリ(entry)とは(集合のリスト ←と同じ長さの値のリスト)のペア

  • (new-entry setl l)でエントリを作れる

  • lookup-in-entryはnameとentryとentry-fを取る


    • entryの名前の集合からnameを探して対応する値を返す

    • entryの中でnameが見つから無かった時はentry-fにnameを渡して呼び出す

    • entryをnamesとvaluesに分解して、lookup-in-entry-helpを呼んでいる



  • テーブル(table)はエントリ(entry)のリスト


    • 環境ともいう



  • extend-tableはエントリを古いテーブルの先頭に付け加え、新しいテーブルを作る

  • lookup-in-tableはnameとtableとtable-fを取る


    • テーブルの中の先頭のエントリから順にnameの値を探して対応する値を返す

    • tableの中でnameが見つから無かった時はtable-fにnameを渡して呼び出す

    • tableから先頭のエントリを取り出してlookup-in-entryを呼んでいる

    • 先頭のエントリの中でnameが見つからなかった時に次のエントリを探せるように、entry-fにtableへの参照を持ったクロージャを渡している



  • 式(Expression)


    • eはexpressionの略

    • タイプが6つある

    • *const

    • *quote

    • *identifier

    • *lambda

    • *cond

    • *application

    • タイプを関数、actionとして表現する

    • 8章のatom-to-functionのようにexpression-to-actionを定義

    • atomならatom-to-action

    • listならlist-to-action


      • carを見て判断





  • expression-to-actionがきちんと動作するならvalueとmeaningを定義出来る

  • valueはSchemeのevalと同じ。引数で式を取る


    • meaningに式と空の環境を渡して呼び出す



  • meaningは式と環境を引数に取る


    • expression-to-actionでタイプの表現、関数を取り出す

    • 式と環境を渡しその関数を呼び出す



  • タイプを表現するアクション達

  • 非基本関数と基本関数


    • 基本関数は何をするものか知っている関数

    • 非基本関数は引数と関数本体によって定義される関数

    • 仮引数と関数本体を覚えておく必要がある。

    • (lambda (x) x)でいうcdrの((x) x)の部分

    • それに加えテーブルを覚えておく。

    • この3つでクロージャレコード



  • evcon


    • null?の質問がないまま再帰しているのでquestion-ofが真になるlineが無かったらエラーが出るため、少なくとも1つの質問は真である必要がある。



  • evlis


    • listの全ての意味をmeaningで求めて新しいlistにして返す、のかな



  • apply


    • primitiveかそうでないか、でapply-primitiveとapply-closureに処理を振り分けてる。




気づき疑問等




  • extend-tableで新しいエントリを先頭につけるのは、carを使って先頭から探るため?

  • p183のadd1?sub1?はadd1、sub1の間違い?

  • *identifierの中のinitial-tableは…

  • evconはeval-condの略?

  • evlisはeval-list?

  • :atom?をatom?だと思っててハマった orz

  • あと:atom?がキーワードとして認識されちゃったのでmy-atom?に変更

  • ページの順番通りに*applicationを定義した後applyを定義してハマった。


    • 最初に*applicationを定義する時、中でapplyを使ってる

    • 自前applyを定義する前に*applicationを定義するとGaucheに元からあるapplyを見ちゃう

    • 自前applyを定義するのを*applicationの前にもってきて解決



  • defineが出てきてないのに「再帰はYコンビネータによって得られるので、必要はありません。」という答え方は素敵だと思った


    • 全部lambdaで書けばdefine使わなくてok的な

    • でも「Scheme修行も見てください。」とのこと。



  • 「Yコンビネータによる変形を行うとインタプリタ上でインタプリタを走らせる事が可能である」


    • 前の章で出てきたYコンビネータがしっかりとインタプリタで動く事を確認してちょっと感動。動きを追ってみたい。

    • loopはYコンビネータで出来るし、evalは今作った。後はreadとprintだけ用意してやればREPLが出来る!?




感想


最後の章でもapplyのところで処理を分けたり、table関連でうまく抽象化しててすごく分かりやすい。


lookup-in-tableの中でlookup-in-entryに渡すentry-fのクロージャ(cdr table)の部分が好き。



(lambda (name)
(lookup-in-table name (cdr table) table-f))


この10章だけでも何回も読めそう。


冒頭にある読者へのガイドラインでは



急いでこの本を読まないでほしい。注意深く読むこと。有益なヒントがテキスト全体にちりばめてある。この本を2回以下で読み切ろうとしないこと。系統的に読むこと。ある章が完全には理解できなければ、次の章はもっと理解できなくなる。質問はだんだん難しくなるように並べてある。前の方が解けないと、後ろのほうはもっと難しい。

と書いてあるけど、もう一周読んでみても楽しめそうです。


前半部分は何度も読んでるけど8, 9, 10とそこらへんは理解度足りてない感じもするのでもうちょい読み込む予定…


最初にエントリをあげたのが2011年4月14日で、今は8月10だから大体4ヶ月ほど。


特にYコンビネータのところでコミットの感覚が20日以上あいてるのでそこが一番難しかったような。


前の方から後ろに行けばいくほど楽しかったです。





2011年8月6日土曜日

メモ



メモ



$ make osx-uninstall
make -f compile/Make_osx.mak uninstall
rm -f /usr/local/lib/libmigemo.1.dylib
rm -f /usr/local/lib/libmigemo.1.1.0.dylib
rm -f /usr/local/lib/libmigemo.dylib
rm -f /usr/local/share/migemo/migemo-dict*
rm -f /usr/local/include/migemo.h
rm -f /usr/local/share/doc/migemo/README_j.txt
rm -f /usr/local/bin/cmigemo
rm -rf /usr/local/share/migemo
rm -rf /usr/local/share/doc/migemo





2011年8月3日水曜日

ApacheでPHPとMySQL動かすまでの設定めも



Apache


最初に入れたPow(MacBook Airを買いました。 - はなちん C-x C-c参照)とポート被っててWeb共有スタート出来なかったので


Pow と Apache を共存させる - すぱぶらの日記


/private/etc/apache2/other/以下に8080.conf作って



Listen 8080

でとりあえず起動するようになった。


localhost:8080でアクセス。


PHP


PHPの設定は/etc/apache2/httpd.confの



#LoadModule php5_module libexec/apache2/libphp5.so

をコメントアウト。


MySQL


本家からダウンロードしてきて入れた!


PATHは/usr/local/mysqlに通した





2011年8月2日火曜日

Vundleをインストール



参考


gmarik/vundle ? GitHub


blog.shu-cream.net: 2011年のVimプラグインの管理はVundleで


手順通り



git clone http://github.com/gmarik/vundle.git ~/.vim/bundle/vundle


とりあえず



set nocompatible
filetype off

set rtp+=~/.vim/bundle/vundle/
call vundle#rc()

" let Vundle manage Vundle
" required!
Bundle 'gmarik/vundle'
Bundle 'sudo.vim'
Bundle 'rails.vim'


これだけ書いて、vim開いて:BundleInstallした。


アップデートは:BundleInstall!


sudo.vimの:w sudo:%覚えた。





2011年8月1日月曜日

MacBook Airを買いました。



買っちゃいました。


備忘録をかねて追記しながら。


f:id:h6n:20110801190310j:image


結構箱でかいと思ったら中に入ってる模様


f:id:h6n:20110801190918j:image


おお


f:id:h6n:20110801191148j:image


ででーん!


f:id:h6n:20110801191452j:image


付属品たち。


f:id:h6n:20110801191548j:image


前使ってたMacBookよりも付属の電源アダプタがちっさくなってる。


f:id:h6n:20110801192125j:image


奇麗ですね。畳の上でもAirは奇麗ですね。


f:id:h6n:20110801192229j:image


薄い!


f:id:h6n:20110801192242j:image


薄さを伝えるために比較写真を。ハッカーと画家より薄い!


f:id:h6n:20110801192413j:image


んで開きました。


f:id:h6n:20110801192517j:image


電源オン、ぼーん。


この瞬間から写真を撮るのを忘れて触りっぱなしという、ブロガーにあるまじき行為。


f:id:h6n:20110801192552j:image


キーボードも光る。かっこいい。かっこよすぎて目が悪くなるのに暗い中使ってしまいそう。


f:id:h6n:20110801194724j:image


もちろんUS配列です。写真が歪んでいても心はUS一直線。


f:id:h6n:20110801192731j:image


初めてマルチタッチのジェスチャー操作を使用して感じたこと


もうマルチタッチ無しには戻れない。今までMacBook2,1を使っていました。Core2Duo、マルチタッチ非対応のままSnow Leopardまで使ってしまった。


こんなに快適だとは思わなかったなー。Magic Trackpad買っておけばよかったと思う。いやほんと。


フルスクリーンアプリで1画面占有して広く使ってそれを3本指ドラッグですいすい切り替えできてすごく楽。


f:id:h6n:20110801224221p:image


3本指でドラッグしながら上に動かすとミッションコントロールの画面が出て、デスクトップ一覧、ウィンドウ一覧が出る。


何枚デスクトップが作れるのか分かんないけどとりあえず10個ぐらい作ってみた。


f:id:h6n:20110801224630p:image


もちろんこの状態でも左右にスクロールでデスクトップの切り替えが出来る。


んでウィンドウ掴んで他のデスクトップに移動する事も出来る。何コレやばい。


後はFirefoxがフルスクリーン等に対応してくれたら幸せだな。Vimperatorがある限りFirefoxを離れる事は出来ないのでw


Launchpadはこんな感じ。ユーティリティのフォルダ開いてみた。iPhoneみたいだね。


f:id:h6n:20110801225836p:image


地味にびっくりしたのがアプリを起動し直すと前に開いていたウィンドウがそのまま戻ってくる事。


便利だけどちょっと怖いなー。


んで、プレビューで見てたの閉じて何も開いてない状態で他のアプリにフォーカス移すと勝手に終了してくれる。こまかい所に手が届くね。


そういえばSafariでGmailにログインしたらMail、iCal、iChatにアカウントを設定しますか?みたいなポップアップが出て、はいを押したらそのまま何もいじる事なくMailでメール読めるようになって、iCalもiChatも出来るようになった。凄く楽や。


そうそう、楽といえばことえりで推測された言葉の候補が出てくる!いいなーこれ。変換中に辞書が出てくるのも良い。


f:id:h6n:20110801230849p:image


f:id:h6n:20110801230844p:image


とりあえずやった事のメモ


いかんせんこのままでは何をいじったか忘れる。


とりあえず列挙




開発云々の下準備


Xcodeを入れ終わったら次はHomebrew ? MacPorts driving you to drink? Try Homebrew!入れてみます。


Installation ? mxcl/homebrew Wiki ? GitHubOS X LionのMacbookAirを買ってからRailsの開発環境整えるためにやったことメモ | 野ログはノロキュアMaxHeartを参考に。


ターミナル開いて



/usr/bin/ruby -e "$(curl -fsSL https://raw.github.com/gist/323731)"


インストール成功したら



brew install git
brew update


後は必要そうなのを入れる。


Rubyとか


brew install readline
bash < <(curl -s https://rvm.beginrescueend.com/install/rvm)
echo '[[ -s "/Users/sei/.rvm/scripts/rvm" ]] && source "/Users/sei/.rvm/scripts/rvm"' >> .bashrc
brew link readline
rvm install 1.9.2 -C --with-readline-dir=/usr/local
rvm install 1.8.7 -C --with-readline-dir=/usr/local
rvm use 1.9.2 --default
curl get.pow.cx | sh


Powのアンインストールは



`curl get.pow.cx/uninstall.sh | sh`


よく分かってないので間違ってるとこいっぱいあるかも。


Powが上手く動いてるか確認するために試しに作ってみる。


ついでにpowderってgemも入れてみる。



gem install sinatra
gem install powder


testappを作る


~/testapp/testapp.rb



require 'sinatra'

get '/' do
'Hello world!'
end


~/testapp/config.ru



require './testapp'
run Sinatra::Application


PowでRuby 1.9.2を使ってくれるように


~/testapp/.rvmrc



rvm 1.9.2


作って



cd testapp
powder


でtestapp.devでアクセスしてHello Worldできたかな。


ふむ、分からん。コピペしまくったから。


Emacs


[brew][lion] OS X Lionにhomebrewでemacsとかをインストール - SOSOG


ここ参考にmd5のとこだけ改変してインストールした。



brew install emacs --cocoa


Ctrl+SpaceでSpotlightが出ちゃうのでCtrl+Option+Spaceに置き換え。


f:id:h6n:20110802032524p:image


Android


feb19.jp blog - Mac OS X Lion に Android SDK を入れる


ここを参考にしながら進めていく。



brew install android-sdk
android


ひたすらSDKのダウンロードが終わるのを待つ。ああ、家がADSLじゃなければと思う瞬間。


寝て起きたら終わってた。NDKも入れとく。



brew install ndk


Aptana


Aptana


授業で使うので。


Vertual Box


Downloads ? Oracle VM VirtualBox


仮想マシン。中身に何か入れるかは決めてない。


おわり


最後かなりずれましたね。何の記事なのやら。


眠たいです。でもすっごく快適です。もう元のマシン、Windows環境には戻れない。


前のMacのデータはそのうち持って来ます。


なんかずっと膝上で使ってたらやっぱり暑いです。(特にXcode入れたあたりからファンが鳴ってる)