2011年9月25日日曜日

Scheme修行16章



TheSeasonedSchemer (5) - /var/log/messages


自分も!をbangと呼ぶの知らなくて今まで「setびっくり!」とか「setびっくら!」って読んでました。


#!をshebangと呼ぶのと似た感じですね。


letでつけた名前は内側のlambdaからしか見えなかったりするので確かに属性みたいな感じ。


15章は1ステップずつ読まないと前の問いが後ろに影響することもあって(define した値にset!してたり)結局テスト書いてないです。


16章もそんな感じでがんがんset!してたのでテスト中途半端にしか書けてないです orz


本に書いてあるコードを1つずつ実行したログを編集して16.logとしてまとめました。


感想


途中まではメモ化にset!を使う話をしている気がしました。




  • まずは普通に再帰

  • 再帰の結果をメモ

  • (deep n)は(cons (deep (- n 1)) '())なので(deep (- n 1))がないか調べる

  • deepの再帰の中でもメモ化したdeepMを呼び出すようにする


その流れで第19の戒律



関数の二度の呼び出しにまたがり貴重なものを覚えておく際には(set! ...)を使用して貴重なものをおぼえておくべし。

が出てきました。


後半はletrecの仕組みとY!コンビネータ、YとY!の違いについて、といった感じがします。


YとY!の違いを理解するのにちょっと時間かかりました orz


この章も深い。


メモ




  • この章もset!ばかりで、テストどうかこう orz


    • 結局中途半端にテスト書きました。



  • deepやsweet-toothの実行結果をset!でlistに保存していく

  • 第19の戒律が出てきた。


    • 1回の呼び出し内で複数回使われる値はletで、複数回にまたがる場合はset!で覚えておく



  • deepM


    • findは値が見つかる場合に呼ばれる


      • 後ほどfindに値が見つからない場合を1行追加



    • findが呼び出せるかはあらかじめdeepMがmember?で調べる

    • この役割分担がいいなぁ

    • deepRを内側に取り込んで簡素化



  • p120まではメモ化の話かな?

  • p121、第17の戒律最終版、xの新しい値がx(自分自身?)を参照する関数のとき、が追加

  • 「架空の名前h1を通して自分自身の再帰的コピーを参照しているだけです」

  • Y!コンビネータ


    • 再帰的な部分だけ残してlengthに特徴的な部分を切り出す

    • Lに(lambda (arg) (h arg))を渡してる


      • hをそのまま渡すと(set! h (L h))になってしまう

      • それだと(L h)となり、hが先に評価される

      • 新しいhになる前のhの値そのものをLに渡してしまわないように、lambdaでくるんでる?





  • letrecはletとset!からなる式の省略らしい。letrecを使ったバージョンがY-bang

  • この流れが適用順手続き的Yコンビネータの導出、らしい


YとY!の違い


「Y!はこの形をした全てのfに対してYと同じ再帰関数を作り出す」


biz関数をYに適用した場合と、Y!に適用した場合とで結果が違う。


違いを確かめるために2つのことを試してみました。




  • biz関数の(lambda (a)の下に(print x)つけたら、Y!だとxがずっと1のままだった。

  • biz関数の(set!の下に(print x)つけるとYは毎回表示、Y!だと1回しか表示されない


よくよく定義を見ると




  • Yは(biz (lambda (arg) ((f f) arg)))の(f f)で自分自身を得る際に毎回bizを呼び出してる

  • Y!は(set! hする時、1回しか(biz (lambda (arg) (h arg)))を呼び出さない


(Y biz)には再帰に(set!の部分が含まれてるけど(Y! biz)では含まれてない、という違い。


Y!だとxは1のままなので終わらないです。


気になること


「ありがとう、Peter J.Landin」とあったので名前で検索したら


関連する項目でISWIM - Wikipediaを見つけ


「J演算子は継続を可能としたもので、Scheme の call/cc は J 演算子を簡略化したものである」


という興味深い記述を見つけました。J演算子…


他にもScheme手習いのYコンビネータの前半部分(lambda (f) (f f))のUコンビネータ、SKIコンビネータなど


そこらへんがっつり調べたり、いい資料あったら教えてもらいたいです。


JavaScript


JavaScriptも手続きオブジェクトがあって面白いですよね。


A re-introduction to JavaScript - MDNやってみます。


JavaScriptでクロージャを云々だとWhat’s a Closure?のレッスンも面白かったです。





2011年9月23日金曜日

7つの言語7つの世界 Io 1日目



探してみよう




確認してみよう




  • Ioは強く型付けされた言語か? 弱く型付けされた言語か?


    • Ioは強く型付けされた言語。1 + "one"はエラー



  • 0、空文字列、nilは真か偽か?


    • 0、空文字列はtrue、nilはfalse

    • (true and 0) println; (true and "") println; (true and nil) println



  • プロトタイプのスロットの確認


    • proto slotNames、protoでプロトタイプを取得してslotNamesメッセージ送る



  • =、:=、::=の違い


    • a = 1はupdateSlot("a", 1)、a := 1はsetSlot("a", 1)、 a ::= 1はnewSlot("a", 1)にコンパイルされる

    • =はスロットに値を入れる。スロットが存在していない場合例外を投げる

    • :=はスロットを作成して値を設定。

    • ::=はスロットとセッター(fooだったらsetFoo)を作成して値を設定




試してみよう




  • ファイルからIoのプログラムを実行


    • $ io -hでヘルプ見れる。普通にファイル名渡せばいいみたい。

    • $ echo '"Hello, Io!" println' > day1.io; io day1.io



  • スロットの名前を指定して格納されているコードを実行



$ io
Io 20090105
Io> a := Object clone
==> Object_0x10268e620:

Io> a fuga := method("fuga" println)
==> method(
"fuga" println
)
Io> a fuga
fuga
==> fuga
Io>


これでいいかな?他の人の見たら



Io> a getSlot("fuga") call
fuga
==> fuga
Io>


でした。


感想等


「問題は何をするか」ではない、「何をしないか」だ


フェリスはある朝突然に - Wikipedia


に出て来る台詞らしい。


かっこいい。


JavaScriptと同じようなプロトタイプベースのオブジェクト指向言語。言語自体は凄くシンプル。


プログラミング言語の仕組みを勉強するために作ったらしい。なんかすごい。


JavaScriptは人気すぎるからIoにした、って本の最初の方で書いてたけど、Ioは日本語の情報少なくてちょっと困りそう。頑張って最後まで読む。


ioに書かれてるfeatures見ると




  • small vm(1万行以下)

  • 複数のVMが同じプロセスで動く

  • ガベコレ、弱い参照

  • アクターベースの並列モデル、コルーチン

  • 64bit C99での実装

  • 組み込み言語

  • 例外


とりあえずbrewで入れました。



$ brew install io

雑記



  • Objectが一番てっぺん、Objectにcloneメッセージ送って新しいオブジェクトを作る。

  • オブジェクトはスロットを持つ。slotNamesというメッセージを送ると持ってるスロットが確認出来る。

  • 代入は=、スロットが存在しないのにFooObject = "foo"するとエラー

  • 無かったら新しく作ってくれるのが:=

  • 全てのオブジェクトはtypeに答える


    • 5 typeするとNumberが帰って来る



  • 大文字で始まる名前のオブジェクトはタイプ

  • 送られてきたメッセージに答えらなかったらプロトタイプに転送する

  • Ioではタイプも、タイプを元に作成されるオブジェクトも、どちらもオブジェクト。

  • メソッドの定義はmethod()、methodのタイプはBlock。メソッドもオブジェクト。

  • getSlotでスロットの値を取得出来る。スロットが無かったら親のスロットを辿る。

  • protoメッセージを送ると自分のプロトタイプが取れる


    • REPLも実はオブジェクトのメソッド内で実行してるのかprotoと打つと親が帰って来る



  • Lobbyに全ての名前が入ってる

  • コレクション


    • List


      • ObjectのlistメソッドでListタイプのデータが作れる

      • Listにはaverage sum at append pop prependなどのメソッドがある。



    • Map


      • Mapはハッシュのようなもの、シンタックスシュガーはない。

      • atPut at asObject asList keys sizeなどのメソッドがある





  • 真偽値


    • true false

    • どちらもシングルトンのオブジェクト、cloneを上書きして自身を返すようにする







7つの言語7つの世界 Ruby 3日目



試してみよう




感想等


3章はRubyのメタプログラミングの紹介、メタプログラミングとはプログラムを書くプログラム

Rubyの機能を使えばDSL(ドメイン固有言語)を構築することが簡単に出来る(らしい)

メタプログラミングRuby欲しくなった。

Rubyの3日分の「試してみよう」の他の人の解答見ると、奇麗なコード多すぎて嫉妬。

読んでる間ずっとリファレンスマニュアルと睨めっこだった。

もっとちゃんとした本を一冊かって頭に叩き込まれるまで勉強したいなぁ。

一番良いのは忘れないように毎日何か書く事だろうけど。書かないと何回も調べたことでも忘れちゃう気がする。

試してみようの3日目

元々定義されてるメソッドと同じheadersが設定されてたらmethod_missing呼ばれない。

なので定義されてるメソッドをundefしていく必要があるみたい。

メソッドをまっさらに消すのをブランクスレートと呼ぶらしい。

メタプログラミングに利用出来る機能



  • オープンクラス


    • クラスを定義した後からでも変更出来る

    • 普通はメソッドを追加する時に変更する

    • メソッドを追加する前に作成したオブジェクトからでも追加したメソッドを呼び出せる

    • DSLを作成する時に便利

  • method_missing


    • phpの__callとか__getのようなものか。

    • 例として出ているローマ字がすごい。

  • モジュール


    • 最も人気のあるスタイル

    • 「マクロと呼ばれるモジュールメソッドを使う」

    • acts_as_csvマクロでdefine_methodを使ってCSVファイルに関する全ての動作を定義(acts_as_csv.rb)

本見ながら書いたもの


















2011年9月22日木曜日

PHPのforeachのちょっと嫌なところ



PHPのforeachの嫌なところが1つあります。


foreach ($a as $k => $v) { ... }の$kと$vが上書きされてしまうところです。




<?php
$name = 'hanachin';
$flat = array(101 => 'Kato', 102 => 'Yoshida', 201 => 'Sato');

echo "Hello, I'm $name", PHP_EOL;
foreach ($flat as $room_no => $name) {
// $name = $flat[$room_no]みたいな処理が入ってる(?)
echo "room #$room_no: $name", PHP_EOL;
}
echo "Hello, I'm $name", PHP_EOL;

# Output:
# Hello, I'm hanachin
# room #101: Kato
# room #102: Yoshida
# room #201: Sato
# Hello, I'm Sato
# --------
?>


$nameが上書きされてしまいました。


参照と組み合わせるともっと厄介です。


foreachで使った参照をunsetしないままforeachを使うと配列の最後の要素を意図せず書き換えてしまうことがあります。



<?php
$name = 'hanachin';
$flat = array(101 => 'Kato', 102 => 'Yoshida', 201 => 'Sato');

echo "Hello, I'm $name", PHP_EOL;
foreach ($flat as $room_no => &$name) {
// $name = &$flat[$room_no]みたいな処理が入ってる(?)
}
// foreachを抜けても$nameは$flatの最後の要素、$flat[201]への参照を持っている

foreach ($flat as $room_no => $name) {
// $name = $flat[$room_no]みたいな処理が入ってる(?)
// $nameは$flat[201]と同じところを指しているので
// $nameと$flat[201]の値が、$flat[$room_no]の値で上書きされていく
echo "room #$room_no: $name", PHP_EOL;
}
echo "Hello, I'm $name", PHP_EOL;

# Output:
# Hello, I'm hanachin
# room #101: Kato
# room #102: Yoshida
# room #201: Yoshida
# Hello, I'm Yoshida
# --------
?>


解決するためにはforeachでリファレンスを使ったら必ずその直後でunsetします。



<?php
$name = 'hanachin';
$flat = array(101 => 'Kato', 102 => 'Yoshida', 201 => 'Sato');

echo "Hello, I'm $name", PHP_EOL;
foreach ($flat as $room_no => &$name) {
}
unset($name); // 参照を削除

foreach ($flat as $room_no => $name) {
echo "room #$room_no: $name", PHP_EOL;
}
echo "Hello, I'm $name", PHP_EOL;

# Output:
# Hello, I'm hanachin
# room #101: Kato
# room #102: Yoshida
# room #201: Sato
# Hello, I'm Sato
# --------
?>


「foreach ($a as $k => $v) {}の$kと$vがforeachの中だけのスコープを持っていて、foreachの外の変数に影響及ぼさないと嬉しいのになぁ」と思いました。まる。


参考


PHP: foreach - Manual


PHP: 変数のスコープ - Manual





7つの言語7つの世界 Ruby 2日目



探してみよう



試してみよう



感想等


感想

クラスさえもClassクラスのインスタンス。全てがオブジェクト。


そしてModule.classはClassで、Module.class.superclassはModuleで…と頭がこんがらがりそう。


mixinの仕組みは便利ですね。Enumerableはいろんな演算を抽象化していて面白い。


試してみようはTree.rbがあんまりすっきり書けてない感じ。


本文に「このレベルの抽象化でも少しは優れたプログラミング言語になるが、Rubyの真の秘術が登場するのはまだまだこれからだ。」と書いているので次の章が楽しみです。


疑問点



  • PHP 5.4のtraitもmixinのようなものなのかな?


メモ



  • 配列やハッシュやシンボルのリテラルは書き方いくつかあるので詳しくはリテラルを見る

  • 配列


    • [ ]や[ ]=はArrayクラスのメソッド、なのでundefined_variable[0] = 'hoge'とか宣言してない変数の[0]に値を入れようとするとメソッドないよとエラーが出る

    • Rangeを渡したり-1を渡したり使いやすい。キュー、リスト、スタック、セットのように使えるし、どんな型でもok多重配列もok



  • ハッシュ


    • 試しに['hoge' => 'hoge', 0 => 'foo']って書いたら{'hoge' => 'hoge', 0 => 'foo'}を要素に持つ配列が出来た。ちょっと予想外

    • 同じシンボルは同じオブジェクト、文字列が必要なわけじゃないけど、名前が必要、そんな時に用いるらしい


      • 名前付きの引数もハッシュで再現出来る、関数の最後の引数を囲むブレースが省略可能なおかげ





  • 「Rubyが本当の力を発揮するのは、コードブロックを使い始めたとき」

  • コードブロック


    • 詳しくはメソッド呼び出し(super・ブロック付き・yield)を参照

    • 名前のない関数のようなもの、関数やメソッドに引数として実行可能なコードを受け渡し出来る

    • 用途


      • ファイルの角行の処理

      • HTTPトランザクション内で処理

      • コレクションに対して複雑な演算

      • 他にも至るところでブロックが使われる



    • Rubyの慣習では1行だけのコードブロックはブレースで、複数業にまたがるコードブロックはdo/endで囲む



  • クラス


    • 継承関係


      • 全てのクラスの親はObject(1.9ではBasicObject)

      • クラスはClassのインスタンス

      • Classのインスタンスはオブジェクトのテンプレート

      • Classの親はModule



    • 慣習、規則


      • クラスは大文字で始まりキャメルケース

      • インスタンス変数とメソッド名は小文字で始まり、区切りにアンダースコア

      • 定数は全て大文字で書く

      • インスタンス変数の先頭には@をつける

      • クラス変数の先頭には@@をつける

      • 判定用の関数とメソッドには通常、疑問符をつける

      • アクセッサを定義するメソッドがModuleで定義されている(class Module)


        • attrとattr_accessorがよく使われる







  • モジュール


    • クラスに混ぜ込んで(mixinして)使う、モジュールで定義した振る舞い、定数がクラスの一部となる

    • モジュールは複数のクラスメソッドに依存していることが多い

    • Javaでは明示的にinterfaceを実装するがRubyではダックタイピングによって暗黙的に



  • mixin


    • Flavorsで初めて導入、SmalltalkやPythonなどでも使われている。

    • 最も重要なmixinはEnumerableとComparable


      • Enumerableはeachを実装しておけばany?とかall?とかselectとかinjectとか便利なメソッドが使えるように

      • Comparableは<=>(宇宙船演算子)を定義しておけば比較演算が出来るようになる






Reia

p24のtree.rbの例に書いてあったもの。


Reia Programming Language


Erlang VM(BEAM)上で動くRuby-likeな言語らしい。


でももう開発止まっててこれ以上何かを追加する計画はないので興味があるならElixirをチェックしろと書いてますね。


面白そう。Erlangの章読んだらまたチェックしたい。


本見ながら書いたもの

tree.rb



to_file.rb



遊び





2011年9月21日水曜日

ローマ字を数値に変換(__callStaticを使って)



毎日PHP書くといいがち書いてなかったので今日はPHPも書きます。


7つの言語7つの世界、Rubyのp33で出てた例は美しかったけどなんか、これだと微妙です。


見た目が美しくない。



マジックメソッドの__callStaticで、呼び出したメソッドの名前(ローマ数字)を数に変換して返しています。





2011年9月17日土曜日

Scheme修行15章



Scheme修行は毎章違う題材が出てきます。前の章の継続も面白かったけど今回のも面白い。


メモ等




  • ここに来て初めてdefineで値に名前をつける。

  • set!の読み方「セット、バン!」

  • set!は値を返さない。defineと似たもの。Lispではsetq(セットキュー、説得)

  • set!すると名前の参照を変更出来る。あたかもxが定義されてないときにdefineで名前をつけるように。

  • lambdaの値部分に2つ式があるのはletやbeginと同じ。2番目の式(最後の式)の値を返す。

  • 別々の関数で同じ名前に対してset!する衝突が起こりえる。それは困る。

  • lambdaをletで囲む


    • あたかも架空の名前x1をdefineしたかのよう

    • 架空の名前の値はない。

    • 架空の名前が何を表しているか覚えておかないといけない



  • 16の戒律「(let...)で定義された名前に対してのみ、(set!...)を使うべし


    • 大域的な名前にset!すると駄目



  • 第17の戒律(予備版)


(let ( (x ...)) ...)に対して(set! x ...)を用いる際には


それらの間には少なくとも1つのlambdaを置くべし




  • letとsetの間にlambdaを入れないで使っても何かを覚える役には経たない

  • 第18の戒律「(set! x ...)はxが参照する値がもはや必要ないときにのみ使うべし」


    • set!すると値への参照がなくなってしまうので。

    • swapを例に

    • letを使って名前をつけるとその値を参照するのに2通りの方法がある




感想


15章ではset!の使い方と破壊的代入の問題点を説明している感じがしました。


ふつーのプログラミング入門だと変数に値を入れるのが関数の定義よりも先に来ますよね。


Scheme手習い、Scheme修行ではアトムから始まって、すぐに関数を定義して、値は引数で取り、関数を組み合わせて抽象化し、わざわざ関数に名前をつけずともY Combinaterがあれば再帰が出来る事を示し、計算結果を覚えるためにletを使い、と、ここまで値にdefineで名前をつける必要がありませんでした。


set!の説明と問題点を示すためだけにdefineで値に名前をつけている気がします。


関数プログラミング的な考えが重用視されてるような感じをちょっと受けています。


次の章が楽しみです。set!の上手い使いどころを示してくれそうな感じ。


# ホワイトボード使ってやるのも楽しそうですね


※ところでこの章、試験なナニを書けない気がします。なので実行ログを残しました。



gosh> (define x
(cons 'chicago
(cons 'pizza '())))
x
gosh> x
(chicago pizza)
gosh> (set! x 'gone)
gone
gosh> x
gone
gosh> (set! x 'skins)
skins
gosh> (define gourmet
(lambda (food)
(cons food (cons x '()))))
gourmet
gosh> x
skins
gosh> (cons x '())
(skins)
gosh> (gourmet 'onion)
(onion skins)
gosh> (set! x 'rings)
rings
gosh> (gourmet 'onion)
(onion rings)
gosh> (define gourmand
(lambda (food)
(set! x food)
(cons food (cons x '()))))
gourmand
gosh> (gourmand 'potato)
(potato potato)
gosh> x
potato
gosh> (gourmand 'rice)
(rice rice)
gosh> x
rice
gosh> (define diner
(lambda (food)
(cons 'milkshake (cons food '()))))
diner
gosh> (define dinerR
(lambda (food)
(set! x food)
(cons 'milkshake (cons food '()))))
dinerR
gosh> (dinerR 'onion)
(milkshake onion)
gosh> x
onion
gosh> (dinerR 'pecanpie)
(milkshake pecanpie)
gosh> x
pecanpie
gosh> (gourmand 'onion)
(onion onion)
gosh> (define omnivore
(let ((x 'minestrone))
(lambda (food)
(set! x food)
(cons food (cons x '())))))
omnivore
gosh> 'minestrone
minestrone
gosh> (omnivore 'bouillabaisse)
(bouillabaisse bouillabaisse)
gosh> (define gobbler
(let ((x 'minestrone))
(lambda (food)
(set! x food)
(cons food (cons x '())))))
gobbler
gosh> (gobbler 'gumbo)
(gumbo gumbo)
gosh> (define nibbler
(lambda (food)
(let ((x 'donut))
(set! x food)
(cons food (cons x '())))))
nibbler
gosh> (nibbler 'cheerio)
(cheerio cheerio)
gosh> (define food 'none)
food
gosh> (define glutton
(lambda (x)
(set! food x)
(cons 'more (cons x (cons 'more (cons x '()))))))
glutton
gosh> (glutton 'garlic)
(more garlic more garlic)
gosh> food
garlic
gosh> x
onion
gosh> (define chez-nous
(lambda ()
(set! food x)
(set! x food)))
chez-nous
gosh> food
garlic
gosh> x
onion
gosh> (chez-nous)
onion
gosh> food
onion
gosh> x
onion
gosh> (define chez-nous
(lambda ()
(let ((a food))
(set! food x)
(set! x a))))
chez-nous
gosh> (glutton 'garlic)
(more garlic more garlic)
gosh> food
garlic
gosh> (gourmand 'potato)
(potato potato)
gosh> x
potato
gosh> (chez-nous)
garlic
gosh> food
potato
gosh> x
garlic
gosh>


リポジトリの方にもcommitしてるのですが、外出先からPDA Net使ってgit pushしようとしたのですが繋がらないため、GitHubの同期はちょっと遅れてしまいそうです。ごめんなさい。





2011年9月16日金曜日

7つの言語7つの世界 Ruby 1日目



Okinawa.rbも立ち上がったみたいだし


Ruby入門のレッスン一覧


こんなすごく便利なサイトもあるし、Rubyもっと覚えたい。


残念ながら今のお仕事で使えるかは微妙。


とりあえずの目標として


Rubyアソシエーション: トップページ


シルバーをを受けてみたい。


いつでも試験を受ける環境はある、実行に移せるかは自分次第、なので頑張るのです。


探してみよう




試してみよう



感想等


RubyはOOPL、ダックタイプ、強い型付け、動的型付け。全てがオブジェクト!(数でさえも)


プログラマの生産性を高めてくれる機能がたくさん。


「人間様が気分よくプログラミングするための言語」Rubyは何を目指すのか - GIGAZINE


を読んだ。楽しそう。続けて2日目読みます。楽しい時間はあっというまだなー。





7つの言語7つの世界を読みます。



7つの言語7つの世界を買ったので読みます。Scheme修行と平行して読む。楽しみ楽しみ。7週間で読めるかは微妙なところだけどw


読んだら友達に貸す。貸したら自分で買いそうだけど。早く貸すためにちゃんとサボらず読む。


「はじめに」の中で書いてあったことを意識しながら読みます。



本書を単に読むだけでは、シンタックスの雰囲気はつかめるだろうが、それ以上は無理だ。

実は演習問題をやらずに1回読みました。それ以上を掴むためにもう一度読みます。



演習問題を自分でコーディングしてみる前にネット上で答えを探すようでは、失敗だ。まず自分で解いてみて、いくつかの問題が解けないことを自分自身で認識するようにしてほしい。

まず、自分で1回解くように頑張ります。僕は怠け癖が強いのでついつい調べてばかりで手動かせない。


でもRubyの1日目を解いてからググったら奇麗な解答を見つけることが出来たので終わったらググるの解禁、むしろ積極的にググって他人のコード見ます。


あと序文はかなり共感出来る。人の真似して書いてるだけでちょっとずつ出来ることが増えてくのだとか、実際に書いてコンパイルとおるように直しているうちに気づくこととか。


ちゃんと読むためにエントリかきました。


早速手を動かして、本読みます。


追記


The Pragmatic Bookshelf | Seven Languages in Seven Weeksから本書のコードをダウンロード出来る。


正誤表もあるので不具合あったらチェックします。





2011年9月14日水曜日

PHPで入力された文字列の長さのフィルタリング



PHP: Filter - Manualを参考に。


文字列の長さもフィルタリングしたい。


ユーザー定義の関数でデータをフィルタリングしたいときはFILTER_CALLBACKフィルタを使う。


例えば1文字以上5文字以下の文字列なら



<?php
function FILTER_VALIDATE_LENGTH($value) {
$len = mb_strlen($value);
if (1 <= $len && $len <= 5) {
return $value;
}
return false;
}

$tests = array(
'', // 空文字列
'', // 1文字
'あいうえお', // 5文字
'あいうえおか', // 6文字
);

foreach ($tests as $test) {
var_dump(filter_var($test, FILTER_CALLBACK, array('options' => 'FILTER_VALIDATE_LENGTH')));
}



$ php foo.php
bool(false)
string(3) "あ"
string(15) "あいうえお"
bool(false)

任意の長さの文字列をフィルタリングしたいなら(ついでにエンコーディングも指定したい場合)



<?php
function makeFilterValidateLength($min, $max, $encoding = null) {
if (is_null($encoding)) {
$encoding = mb_internal_encoding();
}

return function ($value) use ($min, $max, $encoding) {
$len = mb_strlen($value, $encoding);
if ($min <= $len && $len <= $max) {
return $value;
}
return false;
};
}

$tests = array(
'', // 空文字列
'', // 1文字
'あいうえお', // 5文字
'あいうえおか', // 6文字
);

foreach ($tests as $test) {
var_dump(filter_var($test, FILTER_CALLBACK, array('options' => makeFilterValidateLength(5, 5))));
}



$ php foo.php
bool(false)
bool(false)
string(15) "あいうえお"
bool(false)

エンコーディングの指定が省略されてたらmb_internal_encoding()を使うようにする。





PHPのファイルの文法が正しいかどうか確認する





  • lか--syntax-checkオプションを使う。



$ php -l foo.php
$ php --syntax-check foo.php




2011年9月13日火曜日

PHPでフィルタリングを連続して適用したい



日中はずっとPHPと睨めっこです。息抜きに書くPHPも必要。とりあえず、1日1つは息抜きで何かを書きます。



フィルタリングを連続して適用する


1つ前の記事、PHPで入力された文字列の長さのフィルタリング - はなちん C-x C-cで書いたフィルタを連続して適用したかったのでごにょごにょ書いてたらこうなりました。



<?php
function strWithLine($str) {
return str_repeat('-', 8) . $str . str_repeat('-', 8);
}

function makeFilterValidateLength($min, $max, $encoding = null) {
if (is_null($encoding)) {
$encoding = mb_internal_encoding();
}

return function ($value) use ($min, $max, $encoding) {
$len = mb_strlen($value, $encoding);
if ($min <= $len && $len <= $max) {
return $value;
}
return false;
};
}

function makeFilterWrapped($filter = FILTER_UNSAFE_RAW, $options = null) {
return function ($value) use ($filter, $options) {
return filter_var($value, $filter, $options);
};
}

function ret($value) {
return $value;
}

function bind($f, $g) {
return function ($value) use ($f, $g) {
if ($f($value) === false) {
return false;
}
return $g($value);
};
}

$test = 'example@example.com';
$m = 'ret';
$f1 = makeFilterValidateLength(0, 1);
$f2 = makeFilterValidateLength(0, 19);
$g = makeFilterWrapped(FILTER_VALIDATE_EMAIL);
$fail_filters = array(
bind('ret', $f1),
$f1,
bind($f1, 'ret'),
$f1,
bind(bind($m, $f1), $g),
bind($m, bind(function ($x) use($f1) { return $f1($x); }, $g)),
);
$pass_filters = array(
bind('ret', $f2), $f2,
bind($f2, 'ret'), $f2,
bind(bind($m, $f2), $g), bind($m, bind(function ($x) use($f2) { return $f2($x); }, $g)),
);

echo strWithLine('fail_filters'), PHP_EOL;
foreach ($fail_filters as $filter) {
var_dump(filter_var($test, FILTER_CALLBACK, array('options' => $filter)));
}

echo strWithLine('pass_filters'), PHP_EOL;
foreach ($pass_filters as $filter) {
var_dump(filter_var($test, FILTER_CALLBACK, array('options' => $filter)));
}


もっと色々とうまく出来るようになりたい。





2011年9月8日木曜日

PHP技術者認定初級試験の認定証が届きました



今日から初級認定PHPer! ステッカーが1枚ついてました。


MacBook Airにまだステッカー貼ってないんですよね、貼ろうか悩み中です。


11月から始まる上級試験も受けたいと思います。


PHPは便利な関数もいっぱいあるのですが無知のせいで使えてない感じがしてます。


昨日初めてfill_varという超便利な関数を知りました。URLやE-MailアドレスやIPアドレスの検証・サニタイズ等行えます。


資格は上級目指して、普段PHP書くときはPHPらしく書けるように頑張ります。


f:id:h6n:20110908000719j:image





2011年9月7日水曜日

Scheme修行14章



14章では新しく第15の戒律、letが出てきます。進むにつれて第14、第12の戒律を組み合わせて少しずつ奇麗なコードへ。


letccで得た方位磁針を渡してskipするなど前章とちょっとだけ違う使い方をしてるのも面白かったです。


気づいた点等、とりあえずメモ書き。




  • 同じ式が繰り返しでてくるのはまずい


    • 関数を理解するのに同じ式を2回読まないといけない

    • 関数を読んでる人が理解しづらいのと、2回評価するからその分計算が増えるからいけてない



  • 繰り返される式に名前をつけるためにletを使う


    • 再帰関数に名前をつけるのにはletrecを使う(以前の章でやった)

    • letrecは多分let recursiveの略、letは何の略かな?

    • letは以下のλ式のシンタックスシュガー


      • (let ( (x1 α1) ... (xn αn)) β...)

      • ((lambda (x1 ... xn) β...) α1 ... αn)

      • λの仮引数x1...xnがα1...αnに束縛される

      • letrecは複数定義したのを相互に使えるけどletは駄目。

      • α1...αnを評価している環境の違いかな?





  • eqlist?はTheLittleSchemerでは自分で定義してた。(define eqlist? equal?)して代用。

  • letrecとletを使ってrember*を定義


    • avは何の略だろう?



  • 第15の戒律(仮)「繰り返される式の値に名づくるには(let ...)を用うべし。」


    • 「名づくる」「用う」初めて見た



  • rember1*を途中までrember*に空目してた

  • p70のdepth*は書き換えてテスト実行したけど確かに通らなかった


    • lが空か分かる前に(car l)の値に依存してしまっている



  • p73のdepthは非常に読みづらい


    • 1回しか評価されないのにletで名づくるのは読みづらくなったりする



  • 第15の戒律「関数定義において繰り返される式は、当の関数を1回使用するときに2回評価される可能性があるなら、それらの値を名づくるに(let ...)を用うべし。」

  • if文出てきた!


    • もっと前に知っておくべきだった?「何事にも、ふさわしい時と場所があるのです。」

    • (if α β γ)は(cond (α β) (else γ))と同じ

    • condを知ってればすっとifを理解出来る。

    • 答えによって2つに分かれる時ifを使うとcondよりも読みやすくなる



  • 最初のコードから掟に従いつつ構造を考えていくと可読性があがりますね


    • 比較するために1回、値を返すためにもう1回、合わせて2回評価してた

    • letで束縛すると2回評価しないでよくなってコードもすっきり

    • 2つに分岐するだけならifのがすっきり

    • やってることを抽象化してmaxを使えばすっきり

    • リファクタリングってこんな感じなのだろうか



  • letのbody部分に複数の式を置いてbegin的に使うなど

  • 「第14の戒律を用いるときに第13の戒律を忘れてはならない」


    • 関数を書き直していく時、今まで出てきた戒律を意識せねば。



  • letで順番よく実行している途中で答えを見つけたとき、抜け出すために方位磁針skipを使う


    • 継続を取り出してからマイナー関数に渡すことで、マイナー関数の中で値が求まった時に即座に返す事が出来る!



  • letccを使ったrember1*について


    • rember1*の中で、(car l)から何も取り除けなかったら方位磁針を使って戻って来る。

    • 取り除けた時はaを取り除いたリストを作りながら戻って来る。

    • 取り除けなかった時はnoっていうアトムを持って戻って来る。

    • 取り除けたら終わり、取り除けなかったらcdrで再帰

    • 方位磁針を使う事がないと分かっている場合は、0や'()を方位磁針として渡しても大丈夫。



  • tryを使うとちょうすっきり書ける。tryはマクロで書いた。


    • (try x a b)aの中でxを使うとaを抜けて、bを返す

    • 使わずにaを終了した場合、bは実行せず即座に値を返す




感想等


この章は結構ボリュームあった。休憩させるために「象を数えてみましょう。」とかそういうのが出て来るのが多かった気がする。


途中まではletの使い方で、2度評価される式に名前をつけたり、letをbeginのように使う使い方が出てきたり面白い。


後半数ページはletあまり関係なく継続の話だった。


引数でletccの方位磁針を受け取ったり、ifの条件式の中でletccを使うなど今までと違う使い方が出てきてこれもまた興味深い。


あと、tryを使うとなんだかものすっごいすっきり書けますね。


rmから結果を受け取って、rmの外側で成功したか判断して値を返すのではなく、


rm自身に失敗時の処理へ飛ぶ方位磁針を渡して渡しているのが面白い。


方位磁針を使わなかったら失敗時の処理へは飛ばず、rmの値が返る。


rmがその方位磁針を使うか使わないかをrmの内側で制御出来るようなイメージ。


方位磁針を使った時に返す値('no)をいじるともっと色々出来るのかな?


修行読みつつ(読み終わったら、になるかもしれないけど)プログラミングGauche読みます。


次の章への期待


この章まででかなり色々な関数の使い方を覚えました。


15章は表紙の絵だし、タイトルも「大人と子供の違い…」と、一区切り付きそうな印象。


時間をしっかり作りながら読んでいきたいと思います。


そういえば、バイト出始めたのでプライベートな時間ががくっと減って、働きながら勉強してって大変だなと思いました。


いつもおつきあい頂いてありがとうございます。 id:yamanetoshi となく!





2011年9月3日土曜日

Scheme修行13章



letcc - /var/log/messages


フライングされていたので早速13章を読みました。1度読んで2度目読む前にプログラミングGaucheの継続の章を斜め読みしたらちょっとすっきりしました。


その後バスの中でもう一度読んでソースコード書きながら読んで、再度メモを確認しつつ軽く読んだのでエントリを書きます。


letccについて


call-with-current-continuation、その略のcall/cc、継続の事です。


Scheme 修行 - /var/log/messages


を参考にgaucheのマニュアルのletccの項目Gauche ユーザリファレンス: 6.17 制御を読むと


(let/cc var body…)が(call/cc (lambda (var) body …))に展開されると書いてあります。


なのでlet/ccを使うことにしました。


メモ書き




  • (hop M)に遭遇する前にすべきことだった事を全て忘れて(letcc hop M)の値を求めたかのように振る舞う

  • (letcc hop ( (hop)を呼び出すまでの色々な手続き ) M)の色々な手続きを全部忘れてMのところまでジャンプすると考えちゃってもいいのかな

  • hopと唱えて、結果と一緒に正しい場所へ

  • 第14の戒律「(letcc ...)を用いて、値を直ちに、すばやく返すべし。」

  • どこかで覚えてた計算を忘れる

  • intersectallとrember-upto-lastで違うとこ


    • intersectallは結果が何かを知っている


      • 空集合が1つでもあれば、結果は空集合



    • rember-upto-lastはリストの部分が結果に「ない」か知っている


      • リストの中にaを見つけたら、リストの残りに結果がある。前の部分には「ない」。





  • consが結果を待ってるはずなのにconsしないでskipしてたり色々と面白い。

  • 結果をまたずに抜け出すとき、必要のない部分を捨てるときに使うと便利っぽい


    • 計算途中だった値はどこへいっちゃうんだろ



  • 継続についてはもうちょっと別の本やウェブサイト読まないと完全には理解出来てなさそうな感じがする


間違いかな?と思ったもの




  • p45の(null? (cdr lset))の質問の答えは真じゃないかな?

  • p49とp50のJの中のcondのmember?とelse?の結果の式は反対じゃないかな。


感想


再帰がどんなに深くても一番最初のとこまで戻って来れる! すごい!


継続はもっと色々な使い方が出来そうなのでScheme修行読んだらプログラミングGauche読んで再度勉強したい。


そういえば「再起」関数のtypoをオーム社さんのTwitterアカウントにmention飛ばしたんだけど返事が帰ってきてないので後でちゃんと窓口から連絡しようと思います。