Stateモナドの有用性を考えるために書いてみます。
Rangeオブジェクトはカーソルが指すNodeとoffsetを持っています。
getRangeは現在のRangeを返すものとします。
moveはそのRangeにカーソル移動するものとします。
nextNodeとprevNodeはそれぞれ次のNodeと前のNodeを返します。
getRange,nextNode,prevNode,moveは擬似的なものなので、定義は気にしないで下さい。
この4つの関数は参照透過とかそんなわけないのでIOを返します。
これらに対して、4方向にカーソルを動かす関数を定義します。
IOはモナドなのでforが使えます。
predとsuccはscalaz.Enumのシンタックスでデクリメントとインクリメントのようなものです。
実際には移動するときに、offsetなどを調べるものですが、OptionT[IO, Unit]などと複雑になるので省略します。
これらの関数を組み合わせてみます。
さて、これらの関数、ちょっと冗長ですね。
いちいちmoveを実行しているところもいただけません。
これらをStateを使って書きなおしてみます。
squaredは値をペアにして返します。
同じように、合成したStateとそれを使って移動する関数を定義します。
getRangeとmoveの呼び出しは1回で済むようになりました。
movemovemoveというStateを使い回すことも出来ます。
さらに、Stateモナドであることを活かして、次のようなStateを定義することが出来ます。
移動した直後の状態を扱えるのがStateモナドの利点ですね。
最近は大学生がなかなか忙しいです。
俺、定期試験が終わったらScalaz勉強会開くんだ・・・・・
2012年6月27日水曜日
2012年6月23日土曜日
Pythonの復習
最近Pythonさわってなかったので。
なんのへんてつもないコード。
yield使って、generatorにしてみる。
このケースならitertoolsを使ったほうがカッコイイ。
countはnからstep(デフォルトは1)づつ増えていくgeneratorを作る関数です。
mapはいつの間にかイテレータに対応してくれてました。
判定を書く
functoolsとoperatorで関数型っぽく書けて素敵ですね。
functools.partialは部分適用、operator.modは剰余です。
素数列を作る
なかなかいい感じ。
n番目のフィボナッチ数を返す関数
dict使って分岐する
switch的なものはdictで代用できるのでもーまんたいですね。
getの第二引数はキーが存在しない場合返ります。
イテレータ版
Pythonはなかなか関数型言語ちっくに書けて素敵ですね。
Rから始まる4文字のプログラミング言語より関数型っぽいです。
FizzBuzz
なんのへんてつもないコード。
yield使って、generatorにしてみる。
このケースならitertoolsを使ったほうがカッコイイ。
countはnからstep(デフォルトは1)づつ増えていくgeneratorを作る関数です。
mapはいつの間にかイテレータに対応してくれてました。
素数
判定を書く
functoolsとoperatorで関数型っぽく書けて素敵ですね。
functools.partialは部分適用、operator.modは剰余です。
素数列を作る
なかなかいい感じ。
フィボナッチ数列
n番目のフィボナッチ数を返す関数
dict使って分岐する
switch的なものはdictで代用できるのでもーまんたいですね。
getの第二引数はキーが存在しない場合返ります。
イテレータ版
Pythonはなかなか関数型言語ちっくに書けて素敵ですね。
Rから始まる4文字のプログラミング言語より関数型っぽいです。
2012年6月10日日曜日
Proof with Scala
※今回はScala2.10.0-M3を使います。
ある型クラスのインスタンスを定義するとき、何らかの規則を満たす必要があるときがあります。
例えばMonadだとモナド則。
bind,returnを定義するときに、以下のものが満たされないといけません。
bind (return a) f = f a
bind m return = m
bind (bind m f) g = bind m (fun x => bind (f x) g)
しかし、Scalazの型クラスなどはモナド則を満たしているかどうかを検査してくれるわけではありません。
そこで、コンパイル時に規則を満たしているかどうかを検査するように型クラスを定義してみます。
Monoidを例に考えます。
ScalazのMonoidの定義と違うところは、ある型のサブクラスも許容しているところです。
Monoidは以下のものを満たす必要があります。
append zero a = a
append a zero = a
append a (append b c) = append (append a b) c
これをScalaで記述すると
となります。
型が命題でプログラムが証明になります。
つまり、leftIdentity,rightIdentity,associativityを定義出来れば証明できたことになります。
カリー=ハワード同型対応!
自然数を定義します。
自然数をMonoidのインスタンスにします。
コンパイル通ったー!
通らない例を作ってみましょう。
正の整数を定義して、Monoidのインスタンスを考えてみます。
この定義では当然コンパイルは通りませんね。
コンパイルが通るように定義することも多分できないと思われます。(asInstanceOfは使っちゃダメですよ。)
これらのコードを書いてる中で疑問が現れました。
NatInstanceのrightIdentityとassociativityです。
このコード、コンパイルは通らないと思っていたのですが、implicitを付けると通りました。
・・・・・なぜ?
ある型クラスのインスタンスを定義するとき、何らかの規則を満たす必要があるときがあります。
例えばMonadだとモナド則。
bind,returnを定義するときに、以下のものが満たされないといけません。
bind (return a) f = f a
bind m return = m
bind (bind m f) g = bind m (fun x => bind (f x) g)
しかし、Scalazの型クラスなどはモナド則を満たしているかどうかを検査してくれるわけではありません。
そこで、コンパイル時に規則を満たしているかどうかを検査するように型クラスを定義してみます。
Monoidを例に考えます。
ScalazのMonoidの定義と違うところは、ある型のサブクラスも許容しているところです。
Monoidは以下のものを満たす必要があります。
append zero a = a
append a zero = a
append a (append b c) = append (append a b) c
これをScalaで記述すると
となります。
型が命題でプログラムが証明になります。
つまり、leftIdentity,rightIdentity,associativityを定義出来れば証明できたことになります。
カリー=ハワード同型対応!
自然数を定義します。
自然数をMonoidのインスタンスにします。
コンパイル通ったー!
通らない例を作ってみましょう。
正の整数を定義して、Monoidのインスタンスを考えてみます。
この定義では当然コンパイルは通りませんね。
コンパイルが通るように定義することも多分できないと思われます。(asInstanceOfは使っちゃダメですよ。)
これらのコードを書いてる中で疑問が現れました。
NatInstanceのrightIdentityとassociativityです。
このコード、コンパイルは通らないと思っていたのですが、implicitを付けると通りました。
・・・・・なぜ?
2012年6月5日火曜日
わたしのScalazプログラミングその2
型クラスについて。
例によって有理数で。
Groupのインスタンスを定義します。
Groupとは、結合演算子、単位元、逆元を持つもののことです。
動かしてみる。
Groupのインスタンスを定義するだけでこれだけのことができます。
自分でデータ型を定義するときは、インスタンス自体に関数を定義より、データ型にメソッドとして定義したほうがいいかもしれません。
また、Groupのインスタンスからメソッドが定義できます。
乗算、除算も定義してみます。
べんり!
例によって有理数で。
Groupのインスタンスを定義します。
Groupとは、結合演算子、単位元、逆元を持つもののことです。
動かしてみる。
Groupのインスタンスを定義するだけでこれだけのことができます。
自分でデータ型を定義するときは、インスタンス自体に関数を定義より、データ型にメソッドとして定義したほうがいいかもしれません。
また、Groupのインスタンスからメソッドが定義できます。
乗算、除算も定義してみます。
べんり!
2012年6月2日土曜日
わたしのScalazプログラミング
Scalaはオブジェクト指向言語なのですよ。
知ってました?
重要:これから書くコードはとてもメニアックなので参考にしないようにして下さい。
加算と減算を追加してみる。
さて、この2つのメソッド、とても似ていますよね。
抽象化してしまいます。
さて、今日の本題はここからです。
この加算と減算を他の数値型に対応させたいとします。
普通はこのようにオーバーロードを使いますよね。
しかし、+や-はメソッド型ではなく、値型なのでオーバーロードは使用できません。
そこで、オーバーロードを使わず、UnionTypesを使って定義します。
これでもまだ問題があります。
Scalaでは、型パラメータをとる関数を値として定義できません。
そこで、関数のようにふるまう型を自分で定義します。
これで+と-の演算を抽象化し、さらに多相に対応しましたね。
めでたしめでたし。
知ってました?
重要:これから書くコードはとてもメニアックなので参考にしないようにして下さい。
今日は有理数を定義してみます。
加算と減算を追加してみる。
さて、この2つのメソッド、とても似ていますよね。
抽象化してしまいます。
さて、今日の本題はここからです。
この加算と減算を他の数値型に対応させたいとします。
普通はこのようにオーバーロードを使いますよね。
しかし、+や-はメソッド型ではなく、値型なのでオーバーロードは使用できません。
そこで、オーバーロードを使わず、UnionTypesを使って定義します。
これでもまだ問題があります。
Scalaでは、型パラメータをとる関数を値として定義できません。
そこで、関数のようにふるまう型を自分で定義します。
これで+と-の演算を抽象化し、さらに多相に対応しましたね。
めでたしめでたし。
2012年6月1日金曜日
Scalaz7でIterateeとIO
いつものようにTwitterでScalazを検索すると
この様なつぶやきが。
コードはこんな感じ。
fmfm.
先頭行をとって長さをとって行数分ぬりつぶして合計をとっているようですね。
このコードはScalaz6なのですが、Scalaz7でも書けるかなーと思い、ちょっと書いてみました。
違いを1つ1つみていきます。
まず、Scalaz7ではgetReaderLinesがないので、BufferedReaderではなくReaderを使うようにしました。
なので、1行ずつではなく1文字ずつしかみれなくなります。
そこで、改行コードをみるようにします。
改行コードはシステムプロパティーのline.separatorで取得できるとのことなので、sys.propsから取得します。
もとのコードでは、先頭行を取得する為にheadを使っていますが、このコードではtakeWhileを使います。
ここでは、述語として改行コードかどうかの判定をとります。
さて、肝心のIterateeの要素ですが、IoExceptionOr[Char]となっています。
これはその名の通り、IoExceptionとの和で、どちらかが内包されています。
ここではvalueOrを使い、IoExceptionだった場合の値を決め、値を取得しています。
repeatBuildはScalaz6のscalaz.IterV.repeatと同じです。
on[IO]は、Iteratee[E, A]から、IterateeT[E, IO, A]に変換しています。
enumReaderはReaderからEnumeratorを作り、&=はEnumeratorをIterateeに流し込みます。
最後に実行の部分ですが、mainを定義しているわけではありません。
SafeAppはunsafePerformIOを明示的に呼び出さない仕組みで、runをオーバーライドすることで実行できます。
・・・・・とまあこんな感じなのですが、Scalaz6と比べて、かなり違うことが分かりますね。
とくにIteratee。
IterVとIterateeで別々のものになっていましたが、いまはIterateeTのみで大分使いやすくなった気がします。(Iteratee[E, A]はIteratee[E, Id, A]の別名)
ただ、enumReaderLinesのようなものは欲しかった。
IOはMonadIOとかMonadControlIOとかいろいろ高機能になっているのですが、基本的な機能が少ないので、相変わらず残念です。
せめてSourceとReaderとWriterのインスタンスくらい作ってくれればいいのに。
あと入出力系。
超便利とまでは言えないけれど、将来性はありそうなiterateeとeffect。
一度さわってみてはどうでしょう?
finagleわかんないから流れを完全無視して、「BufferedReaderを読むときにどうやって回すよ?」の件を、scalaz iterateeで解いてみた。BufferedReaderの文字数を数えるだけ。 gist.github.com/2842998 #akskscala
— Hirokazu NISHIOKAさん (@nisshieeorg) 5月 31, 2012
この様なつぶやきが。
コードはこんな感じ。
fmfm.
先頭行をとって長さをとって行数分ぬりつぶして合計をとっているようですね。
このコードはScalaz6なのですが、Scalaz7でも書けるかなーと思い、ちょっと書いてみました。
違いを1つ1つみていきます。
まず、Scalaz7ではgetReaderLinesがないので、BufferedReaderではなくReaderを使うようにしました。
なので、1行ずつではなく1文字ずつしかみれなくなります。
そこで、改行コードをみるようにします。
改行コードはシステムプロパティーのline.separatorで取得できるとのことなので、sys.propsから取得します。
もとのコードでは、先頭行を取得する為にheadを使っていますが、このコードではtakeWhileを使います。
ここでは、述語として改行コードかどうかの判定をとります。
さて、肝心のIterateeの要素ですが、IoExceptionOr[Char]となっています。
これはその名の通り、IoExceptionとの和で、どちらかが内包されています。
ここではvalueOrを使い、IoExceptionだった場合の値を決め、値を取得しています。
repeatBuildはScalaz6のscalaz.IterV.repeatと同じです。
on[IO]は、Iteratee[E, A]から、IterateeT[E, IO, A]に変換しています。
enumReaderはReaderからEnumeratorを作り、&=はEnumeratorをIterateeに流し込みます。
最後に実行の部分ですが、mainを定義しているわけではありません。
SafeAppはunsafePerformIOを明示的に呼び出さない仕組みで、runをオーバーライドすることで実行できます。
・・・・・とまあこんな感じなのですが、Scalaz6と比べて、かなり違うことが分かりますね。
とくにIteratee。
IterVとIterateeで別々のものになっていましたが、いまはIterateeTのみで大分使いやすくなった気がします。(Iteratee[E, A]はIteratee[E, Id, A]の別名)
ただ、enumReaderLinesのようなものは欲しかった。
IOはMonadIOとかMonadControlIOとかいろいろ高機能になっているのですが、基本的な機能が少ないので、相変わらず残念です。
せめてSourceとReaderとWriterのインスタンスくらい作ってくれればいいのに。
あと入出力系。
超便利とまでは言えないけれど、将来性はありそうなiterateeとeffect。
一度さわってみてはどうでしょう?
登録:
投稿 (Atom)