2011年12月25日日曜日

Kleisli

Kleisliを忘れてました。

Kleisli

Kleisliはある入力をとり、出力をコンテナで包むものです。
Scalazの例でよく出てくる☆はこいつです。

lazy val f: Kleisli[Option, Int, String] = kleisli(5.shows +>: _.shows.some)
f(5) assert_=== Some("55")
lazy val g: Kleisli[Option, String, Int] = ☆(_.parseInt.toOption)
g("5") assert_=== Some(5)
view raw kleisli1.scala hosted with ❤ by GitHub

Kleisliの合成には、>=>と<=<があります。

(f >=> g).apply(5) assert_=== Some(55)
(f <=< g).apply("5") assert_=== Some("55")
(f <=< g).apply("Scalaz") assert_=== None
view raw kleisli2.scala hosted with ❤ by GitHub

Function1W#kleisliは結果をコンテナで包むKleisliをつくります。

lazy val h: Int => Int = _ |+| 2
h.kleisli[NonEmptyList].apply(5) assert_=== NonEmptyList(7)
view raw kleisli3.scala hosted with ❤ by GitHub

Kleislis#askはKleisliにおける恒等関数をつくります。

ask[NonEmptyList, Int].apply(5) assert_=== NonEmptyList(5)
(ask[Option, Int] >=> f).apply(5) assert_=== f(5)
view raw kleisli4.scala hosted with ❤ by GitHub

その他のメソッド

f =<< 0.some assert_=== Some("50")
f =<< none assert_=== None
h.kleisli[NonEmptyList].compose(_.list).apply(5) assert_=== List(7)
(h.kleisli[PartialApply1Of2[Validation, NumberFormatException]#Apply].compose(_.toOption) >=> f).apply(5) assert_=== Some("57")
f.traverse(nel(5, 5)) assert_=== Some(NonEmptyList("55", "55"))
g.traverse("Scalaz".wrapNel) assert_=== None
view raw kleisli5.scala hosted with ❤ by GitHub

  • =<<
    • コンテナの要素をKleisliに適用
  • compose
    •  出力のコンテナを変える。
  • traverse
    • 要素をコンテナで包む。

KleisliはA => M[B]の形の関数で、合成ができて、☆という印象。
scalaz.httpの資料で、routingにKleisliを使っています。
"scalaz http kleisli"でググるとでてきます。

2011年12月24日土曜日

State, StateT

クリスマスイブらしいよ!
私は家で引きこもってるけど!
State

状態を保持する計算に用いられます。

val s = for {
i <- init[Int]
_ <- modify[Int](_ |+| 5)
j <- gets[Int, Int](_ |+| 5)
} yield i |+| j
s ! 0 assert_=== 10
s ! 5 assert_=== 20
view raw state1.scala hosted with ❤ by GitHub

Stateは!で値を、~>で状態を、applyで両方をとりだせます。
値、状態を取り出すときには、初期状態を与えなければなりません。

val s = (put(5) >|> state[Int, Int](s => (s * 2, s + 10)))
s ! mzero[Int] assert_=== 15
s ~> mzero[Int] assert_=== 10
s(mzero[Int]) assert_=== (10, 15)
view raw state2.scala hosted with ❤ by GitHub


値や状態を操作するための関数はStatesに定義されています。

init

状態で値を初期化します。

put

状態を上書きします。

gets

状態から値を更新します。

modify

状態から状態を更新します。

state

状態から値と状態を更新します。


IdentityにもStateを作る関数が定義されています。

state

呼び出し元を初期値にします。

constantState

呼び出し元を初期値にし、初期状態を与えます。

val s = for {
i <- 10.state[Int]
j <- gets[Int, Int](_ |+| 5)
k <- 10.constantState(5)
} yield i |+| j |+| k
s ! 5 assert_=== 30
s ! 10 assert_=== 35
s ~> 0 assert_=== 5
view raw state3.scala hosted with ❤ by GitHub

State#withsは入力される状態を更新します。

init[Int].withs(_ |+| 5) ~> 5 assert_=== 10
5.state[Int].withs(_.times(2)) ~> 5 assert_=== 10
put(5).withs(_ |+| 100) ~> 10 assert_=== 5
view raw state4.scala hosted with ❤ by GitHub

StateT


モナド変換子版もあります。

val s = for {
i <- stateT[Option, Int, Int](_.some <|*|> 100.some)
j <- stateT[Option, Int, Int](s => (s + 100).some <|*|> s.some)
} yield i |+| j
s ! 100 assert_=== Some(200)
s ~> 100 assert_=== Some(200)
view raw statet1.scala hosted with ❤ by GitHub

mapsにより別のモナドにmapすることもできます。

val s = for {
i <- stateT[Option, Int, String](_.some <|*|> "Scala".some).maps {
case Some((s, a)) => List((s |+| 2, a |+| "z"), (s.times(2), a |+| "ちゃん"))
case None => nil
}
j <- stateT[List, Int, String](s => (s |+| 100, s.shows |+| "倍かわいい").pure[List])
} yield i |+| j
s ! 10 assert_=== List("Scalaz12倍かわいい", "Scalaちゃん20倍かわいい")
view raw statet2.scala hosted with ❤ by GitHub

Writerは結合していくことしか出来ませんでしたが、Stateではもう少し自由度が高いというイメージです。
ScalaはvarがあるからStateモナドとかいらないのでは?と思っていましたが、実際に調べて書いてみると可変な参照とはまた違ったもので、これはこれで使い方がありそうです。
STモナドはいりません。

2011年12月23日金曜日

Writer, WriterT

Identity, MA, MABで使う型クラスはほとんど書いたので、モナドを書いていこうと思います。

Writer

計算中の値とは別にもう1つログを作ります。

val result = for {
i <- 100.set("Hello")
j <- 100.set("World")
} yield i + j
result.value assert_=== ("HelloWorld", 200)
view raw writer1.scala hosted with ❤ by GitHub

値とログはoverとwrittenで取り出せます。

result.over assert_=== 200
result.written assert_=== "HelloWorld"
view raw writer2.scala hosted with ❤ by GitHub

Writers#writerで直接インスタンスを作ることも出来ます。

val result = for {
i <- writer("Scalaちゃん".wrapNel, 3)
j <- writer("イカちゃん".wrapNel, 4)
} yield i * j
result.value assert_=== (NonEmptyList("Scalaちゃん", "イカちゃん"), 12)
view raw writer3.scala hosted with ❤ by GitHub

WriterT

Writerのモナド変換子バージョン。

type ScalaChan[A] = WriterT[Option, String, A]
val result = for {
i <- "Scala".some.put("Hello"): ScalaChan[String]
j <- "Scalaz".some.putWith(_.shows.dual |+| "World".dual): ScalaChan[String]
} yield i |+| j
result.value assert_=== Some(("HelloWorldScalaz", "ScalaScalaz"))
view raw writert1.scala hosted with ❤ by GitHub

WriterTに定義してある型クラスのインスタンスは全て[α]WriterT[M, W, α]となっているので、BindやFunctorのインスタンスを利用するには、型の別名が必要みたいです。
put, putWithの他に、liftw, liftwWith, writerTがあります。

type Ikamusume[A] = WriterT[List, NonEmptyList[String], A]
val result = for {
i <- List("Scalaちゃん", "イカ娘").liftw[NonEmptyList].apply("Hello"): Ikamusume[String]
j <- List("Scala", "Scalaz").liftwWith[NonEmptyList].apply(_ |+| "World"): Ikamusume[String]
} yield i |+| j
result.value assert_=== List((NonEmptyList("Hello", "ScalaWorld"), "ScalaちゃんScala"), (NonEmptyList("Hello", "ScalazWorld"), "ScalaちゃんScalaz"), (NonEmptyList("Hello", "ScalaWorld"), "イカ娘Scala"), (NonEmptyList("Hello", "ScalazWorld"), "イカ娘Scalaz"))
((writerT(("Hello", 11).some): ScalaChan[Int]) >|> (writerT(("World", 13).some): ScalaChan[Int])).value assert_=== Some(("HelloWorld", 13))
view raw writert2.scala hosted with ❤ by GitHub

Writerは使えそうだけど使い方がわからないモナドの一つでしたが、モナド変換子の使い方もわかったし、これからはロジックの中に組み込んでいけそうです。

Foldable

冬休み入ったのでのびのびひきこもりたいとおもいます。

Foldable

畳み込み関数を持ちます。
最低限実装しなければならないものはfoldRightかfoldMapです。

MA#foldMap

foldMapは要素をMonoidへ変換し、結合します。

case class ScalaChan[A](values: A*)
implicit def ScalaChanFoldable = new Foldable[ScalaChan] {
override def foldMap[A, M: Monoid](t: ScalaChan[A], f: (A) => M): M = t.values.map(f).fold(mzero[M])(_ |+| _)
}
ScalaChan(1, 2, 3, 4).foldMap(identity) assert_=== 10
view raw foldable1.scala hosted with ❤ by GitHub

MA#foldr, MA#foldl

右畳み込みと左畳み込み。

nel("Hello", "Scalaz").foldr(none[String])(_.some |+| _) assert_=== Some("HelloScalaz")
List('Scalaz, 'Scala).foldl('Scalaちゃん.wrapNel)(_ |+| _.wrapNel) assert_=== NonEmptyList('Scalaちゃん, 'Scalaz, 'Scala)
view raw foldable2.scala hosted with ❤ by GitHub

MA#foldl1, MA#foldr1

foldの初期値をなくしたもの。
失敗した場合はNoneが返る。

nil[Int].foldl1(_ * _) assert_=== None
nel(1, 2, 3).foldr1(_ * _) assert_=== Some(6)
view raw foldable3.scala hosted with ❤ by GitHub

MA#foldLeftM, MA#foldRightM

モナドに包み、合成します。

nel(3, 4, 6).foldRightM(6)((a, b) => b +>: a.wrapNel) assert_=== NonEmptyList(6, 3, 4, 3, 6, 3, 4, 3)
nel("10", "Scala").foldLeftM(10)((i, s) => s.parseInt.map(_ |+| i).toOption) assert_=== None
view raw foldable4.scala hosted with ❤ by GitHub

MA#all, MA#∀, MA#any, MA#∃, MA#element, MA#∋, MA#∈:

allとanyは述語を、elementは要素を渡します。
∀, ∃, ∋, ∈:はエイリアスです。

nel(1, 3, 5).all(_ % 2 /== 0) assert_=== true
nel(1, 3, 6) ∀ (_ % 2 /== 0) assert_=== false
none[Int].any(_ gt 0) assert_=== false
1.some ∃ (_ gt 0) assert_=== true
List(10, 20, 30).element(30) assert_=== true
List(10, 11, 12) ∋ 13 assert_=== false
11 ∈: List(10, 11, 12) assert_=== true
view raw foldable5.scala hosted with ❤ by GitHub

MA#empty, MA#count, MA#foldIndex

emptyは空かどうか、countは要素の数、foldIndexはインデックスの値を取得します。
foldIndexは失敗した場合例外を投げます。

nil[String].empty assert_=== true
nel(1, 2, 4).count assert_=== 3
100.some.foldIndex(0) assert_=== 100
view raw foldable6.scala hosted with ❤ by GitHub

MA#listl, MA#listr, MA#stream

listl, listrはListに、streamはStreamにまとめます。
listlはfoldlで、listrはfoldrで実装されています。

nel(1, 2, 3).listr assert_=== List(1, 2, 3)
'Scalaz.some.listr assert_=== List('Scalaz)
"Hello".show.stream.take(3) assert_=== Stream('H', 'H', 'H')
"Hello".some.stream.take(3) assert_=== Stream("Hello")
view raw foldable7.scala hosted with ❤ by GitHub

MA#maximum, MA#minimum

要素の中から最大値、最小値を取得します。
要素が存在しない場合、Noneが返ります。

"Scalaz".show.maximum assert_=== Some('z')
none[Int].maximum assert_=== None
nel(3, 2, 1, 2, 3).minimum assert_=== Some(1)
nil[String].minimum assert_=== None
view raw foldable8.scala hosted with ❤ by GitHub

MA#selectSplit, MA#splitWith

selectSplitは述語が真の連続する要素を集めます。
偽の要素は捨てられます。

splitWithは述語が真か偽に変わるまで要素を集めます。

nel(0, 1, 1, 2, 3, 5).selectSplit(_ % 2 /== 0) assert_=== List(List(1, 1), List(3, 5))
346.some.selectSplit(_ === 345) assert_=== Nil
import Digit._
11235L.digits.splitWith(_.toInt % 2 === 0) assert_=== List(List(_5, _3), List(_2), List(_1, _1))
"Scalaちゃん".show.splitWith(_ === 'a') assert_=== List(List('S', 'c'), List('a'), List('l'), List('a'), List('ち', 'ゃ', 'ん'))
view raw foldable9.scala hosted with ❤ by GitHub

畳み込み関数は汎用性が高いのでFoldableが定義されるだけでこれだけの関数が使えるようになります。
前に紹介したTraverseは畳み込み関数が定義されていると定義がしやすかったのですが、Foldableは継承されていません。
しかし、Scalaz7ではTraverseがFoldableを継承するように変更されています。

2011年12月22日木曜日

Reducer, Generator

昨日は #rpscala の忘年会がありました。
技術的な話がいっぱいで楽しかったです。
私も頑張らねば・・・!

Reducer

ある型CをMonoidである型Mへとマッピングするものです。

Identity#unit

値をモノイドへ変換します。

implicit lazy val m = IntProductReducer
implicit lazy val l = ListReducer[Int]
1.unit[IntMultiplication] assert_=== (1 ∏)
1.unit[List[Int]] assert_=== List(1)
view raw reducer1.scala hosted with ❤ by GitHub

Identity#cons, Identity#snoc

値と、モノイドである値を結合します。

5.cons(2 ∏) assert_=== (10 ∏)
(3 ∏).snoc(4) assert_=== (12 ∏)
5.cons(nil[Int]) assert_=== List(5)
List(1).snoc(1) assert_=== List(1, 1)
view raw reducer2.scala hosted with ❤ by GitHub

Identity#unitPure

モノイドへ変換した後、値を包みます。

1.pureUnit[List, IntMultiplication] assert_=== List(1 ∏)
100.pureUnit[Option, List[Int]] assert_=== Some(List(100))
view raw reducer3.scala hosted with ❤ by GitHub

MA#foldReduce

指定した型にまとめます。

List(1, 2, 3, 4).foldReduce[IntMultiplication] assert_=== (24 ∏)
nel(1, 2, 3, 4).foldReduce[List[Int]] assert_=== List(1, 2, 3, 4)
implicit lazy val s = DualReducer[String]
nel("Hello", "World").foldReduce[Dual[String]].value assert_=== "WorldHello"
view raw reducer4.scala hosted with ❤ by GitHub

Generator

Reducerを使ってコンテナの要素をまとめます。

GeneratorオブジェクトにはGeneratorのインスタンスが定義されており、Generator#reduceの実装が違います。

Generator#toとGenerator#fromはReducerと初期値とコンテナを渡します。
Generator#reduceはZeroが初期値となります。

Generator.FoldrGenerator[List].from(StreamReducer[String], List("Scala", "Scalaz"), Stream.empty) assert_=== Stream("Scala", "Scalaz")
Generator.FoldlGenerator[List].to(FirstReducer[String], mzero[FirstOption[String]], List("Scala", "Scalaz")) assert_=== "Scala".pure[FirstOption]
Generator.FoldMapGenerator[List].reduce(LastReducer[String], List("Scala", "Scalaz")) assert_=== "Scalaz".pure[LastOption]

Reducerのインスタンスはデフォルトでimplicit parameterではないので、いちいち宣言しないといけません。
unitやconsは普通に使える関数なだけに、とてももったいなく感じます。
しかし、Scalaz7では全てimplicitになっているので、Reducer関連の関数は使いやすくなるだろうと思います。

2011年12月20日火曜日

Category, Endo, Dual

Category

けんろん!

圏論の基礎を読んでいるのですが高校数学では太刀打ち出来ませぬ。

Categoryはcompose(合成関数)、id(恒等関数)を持ちます。

MAB#>>>, MAB#<<<, MAB#⋙, MAB#⋘

(f >>> g).apply(x)はg(f(x))、(f <<< g)(x)はf(g(x))と同じです。

⋙は>>>の、⋘は<<<のエイリアスです。

lazy val f: Int => Int = _ + 2
lazy val g: Int => Int = _ * 2
(f >>> g).apply(5) assert_=== 14
(f <<< g).apply(5) assert_=== 12
(f.promise >>> g.promise).apply(3).get assert_=== (f.promise >=> g.promise).apply(3).get
view raw category1.scala hosted with ❤ by GitHub

Endo

Endomorphismと言うらしい?
早く可換図に書いてあることがわかるようになりたいですね・・・

EndoはA => AのNewType。
つまり、入力と出力が同じ関数です。

Function1W#endo

Function1[A, A]をEndo[A]に変換します。

(f |+| g).apply(5) assert_=== 17
(f.endo |+| g.endo).apply(5) assert_=== 12
mzero[Endo[Int]].apply(5) assert_=== 5
view raw endo1.scala hosted with ❤ by GitHub

EndoはMonoidで、|+|は関数合成、mzeroは恒等関数が返ります。

Dual

そうつい!

DualはMonidで、結合時に左辺と右辺を入れ替えます。

Identity#dual,  Identity#σ

dualはDualのインスタンスを返します。
σはdualのエイリアスです。

"1" |+| "2" assert_=== "12"
(("1".dual |+| "2".dual): String) assert_=== "21"
(f.endo.dual |+| g.endo.dual).apply(5) assert_=== 14
view raw dual1.scala hosted with ❤ by GitHub

Dualがとる型はMonoidに限りませんが、今のところMonoid以外で特殊な動きはしません。

今回はCategoryはあまり深くまで調べませんでしたが、Categoryオブジェクトをみると意味不明用途不明なものがたくさんあります。
使い道などがわかったら是非教えて下さい!

2011年12月19日月曜日

IterV, Enumerator

一昨日Pythonでも書いたので書いておく。

IterV

IterVはIterateeです。
ストリームをイテレートするものと考えて下さい。
ストリームを表すものとしてEnumeratorが定義されています。

IterV#applyによりEnumeratorをイテレートし、IterV#runで実行されます。

import IterV._
implicit lazy val StreamEnumerator: Enumerator[Stream] = new Enumerator[Stream] {
def apply[E, A](e: Stream[E], i: IterV[E, A]): IterV[E, A] = e match {
case Stream() => i
case x #:: xs => i.fold(done = (_, _) => i, cont = k => apply(xs, k(El(x))))
}
}
head(Stream(3, 4, 6)).run assert_=== Some(3)
view raw iterv1.scala hosted with ❤ by GitHub

Enumerator#applyはコンテナとIterVをとり、コンテナをイテレートする関数が定義されます。

IterV#foldは、計算が終了した場合は結果と入力をとり、計算が途中の場合は入力から次の計算を取り出す関数をとり、何らかの値を返します。

入力にはEmpty, El, EOFがあり、それぞれデータなし、データあり、データの終わりを表します。

IterVには標準でいくつかの操作が定義されています。

IterV.head

ストリームを消費して、先頭要素をOptionで返します。

IterV.peek

先頭要素を返します。
こちらはストリームを消費しません。

IterV.length

ストリームの長さを取得します。

IterV.drop

指定した数だけストリームを消費します。

IterV.collect

指定した型に変換します。

IterV.groupBy

先頭要素と各要素をとる述語が真である限り、要素を集めます。

IterV.takeWhile

述語が真のあいだ、要素を集めます。

IterV.reversed

要素の順序を逆にしたコンテナを返します。

IterV.repeat

Iterateeを繰り返し、結果を集めます。

head(Stream(1, 2, 3)).run assert_=== Some(1)
peek(Stream(1, 2, 3)).run assert_=== Some(1)
length(Stream(1, 2, 3)).run assert_=== 3
drop(2)(Stream(1, 2, 3)).run assert_=== ()
collect[Int, List].apply(Stream(1, 2, 3)).run assert_=== List(1, 2, 3)
groupBy[Int, List](_ === _).apply(Stream(1, 1, 2, 1, 1, 2)).run assert_=== List(1, 1)
takeWhile[Int, List](_ % 2 === 0).apply(Stream(2, 4, 5, 6)).run assert_=== List(2, 4)
reversed[Int, List](ListReducer)(Stream(1, 2, 3)).run assert_=== List(3, 2, 1)
repeat[Int, List[Int], List](groupBy[Int, List](_ === _)).apply(Stream(1, 1, 2, 1, 1, 2)).run assert_=== List(List(1, 1), List(2), List(1, 1), List(2))
peekDoneOr[Int, List[Int]](5.pure[List], i => takeWhile(_ lt 3))(Stream(1, 2, 3)).run assert_=== List(1, 2)
view raw iterv2.scala hosted with ❤ by GitHub

そして、Iterateeは合成が可能です。

(drop[Int](2) >|> length).apply(Stream(1, 2, 3)).run assert_=== 1
(drop[Int](1) >|> collect[Int, List]).apply(Stream(1, 2, 3)).run assert_=== List(2, 3)
(head[Int] >>= (o => head.map(_ |+| o))).apply(Stream(1, 5, 3)).run assert_=== Some(6)
view raw iterv3.scala hosted with ❤ by GitHub

scalaz.effectsパッケージではIterateeを使った入力ストリームがあります。
あまり詳しく書いていませんが、Scalaz.effectsについてを書いたので興味があったら見てください。

いまではWeb FrameworkのPlay!にも存在します。
http://playframework.github.com/api/scala/#play.api.libs.iteratee.package
今後の入出力操作の標準となるかもしれないので勉強しておいて損はないはずです。

2011年12月18日日曜日

Digit

漢数字パーサをゴルフしてたので今日はDigit。

Digit

数字を表します。
Digitオブジェクトにこれを継承した0から9までの数字が定義されています。

toInt, toChar, toLong

import Digit._
_1.toInt assert_=== 1
_9.toChar assert_=== '9'
_0.toLong assert_=== 0L
view raw digit1.scala hosted with ❤ by GitHub

Digits

DigitsにはdigitsとLongからDigit、DigitからLongへ変換するimplicit conversionが定義されています。

digitsは_0から_9までをもつListです。

1L |+| _1 assert_=== 2L
digits(1) |+| 1L assert_=== _2
view raw digit2.scala hosted with ❤ by GitHub

MA#digits, MA#traverseDigits, MA#longDigits

digitsはコンテナが内包するCharをDigitへ変換します。
変換に成功した場合はSome、失敗の場合はNoneが返されます。

traverseDigitsは成功した場合、コンテナがSomeで包まれます。

longDigitsは内包されたDigitをLongへ畳み込みます。
この時先頭の0は無視されます。

"1a3".show.digits assert_=== List(Some(_1), None, Some(_3))
"12a".show.traverseDigits assert_=== None
"123".show.traverseDigits assert_=== Some(List(_1, _2, _3))
digits.longDigits assert_=== 123456789L
view raw digit3.scala hosted with ❤ by GitHub

最後にたかはしさんからforkしたコード。

import scalaz._
import Scalaz._
import scala.util.parsing.combinator._
object KanjiNumberParser extends RegexParsers {
def one = "一" ^^^ digits(1)
def two = "二" ^^^ digits(2)
def three = "三" ^^^ digits(3)
def four = "四" ^^^ digits(4)
def five = "五" ^^^ digits(5)
def six = "六" ^^^ digits(6)
def seven = "七" ^^^ digits(7)
def eight = "八" ^^^ digits(8)
def nine = "九" ^^^ digits(9)
def oneDigit: Parser[Digit] = one | two | three | four | five | six | seven | eight | nine
def ju = opt(oneDigit) <~ "十" ^^ { _ | digits(1) }
def hyaku = opt(oneDigit) <~ "百" ^^ { _ | digits(1) }
def sen = opt(oneDigit) <~ "千" ^^ { _ | digits(1) }
def threeDigits = opt(sen) ~ opt(hyaku) ~ opt(ju) ~ opt(oneDigit) ^^ {
case a ~ b ~ c ~ d => (a +>: b +>: c +>: d +>: nil).map(_.orZero)
}
def man = opt(threeDigits) <~ "万" ^^ { _ | 10000L.digits }
def oku = opt(threeDigits) <~ "億" ^^ { _ | (10000L * 10000L).digits }
def cho = opt(threeDigits) <~ "兆" ^^ { _ | (10000L * 10000L * 10000L).digits }
def kanjiNumber = opt(cho) ~ opt(oku) ~ opt(man) ~ opt(threeDigits) ^^ {
case a ~ b ~ c ~ d => ~(a |+| b |+| c |+| d)
}
def parse(in: String) = parseAll(kanjiNumber, in)
}
object Main extends App {
KanjiNumberParser.parse("千五百兆二千二億三千五百十九万百一").map(_.longDigits assert_=== 1500200235190101L).getOrElse(throw new RuntimeException)
}

ただDigitを使ってみたかっただけ。
数をListとして操作できるのも面白いなと思いました。

Memo

Memo

メモ化!

恒例のフィボナッチ数列を書いてみる。

scala> def time[A](f: => A): A = {
| val s = System.nanoTime
| val x = f
| val e = System.nanoTime
| (((e - s) / 1000).toDouble / 1000000).println
| x
| }
time: [A](f: => A)A
scala> object Fib {
| def unapply(n: Long): Option[Long] = (n >= 2).option(n - 2)
| }
defined module Fib
scala> lazy val fib: Long => Long = {
| case 0 => 0
| case 1 => 1
| case Fib(n) => fib(n) + fib(n + 1)
| }
fib: Long => Long = <lazy>
scala> time(fib(40))
4.055657
res6: Long = 102334155
scala> time(fib(43))
16.81403
res7: Long = 433494437
view raw memo1.scala hosted with ❤ by GitHub

メモ化してみる。

scala> implicit lazy val m = immutableHashMapMemo[Long, Long]
m: scalaz.Memo[Long,Long] = <lazy>
scala> val memofib = m(fib)
memofib: Long => Long = <function1>
scala> val memofib = !fib
memofib: Long => Long = <function1>
scala> time(memofib(40))
4.034974
res8: Long = 102334155
scala> time(memofib(40))
2.8E-5
res9: Long = 102334155
scala> time(memofib(43))
16.980203
res10: Long = 433494437
scala> time(memofib(43))
2.5E-5
res11: Long = 433494437
view raw memo2.scala hosted with ❤ by GitHub

m(fib)はMemo#applyが呼ばれ、メモ化された関数が返ります。
!fibはFunction1Wに暗黙の型変換され、unary_!が呼ばれています。
unary_!は暗黙のパラメータでMemoをとり、メモ化します。

実装をメモ化する。

scala> implicit lazy val m = mutableHashMapMemo[Long, Long]
m: scalaz.Memo[Long,Long] = <lazy>
scala> lazy val mfib: Long => Long = m {
| case 0 => 0
| case 1 => 1
| case Fib(n) => mfib(n) + mfib(n + 1)
| }
mfib: Long => Long = <lazy>
scala> time(mfib(43))
0.002366
res13: Long = 433494437
scala> time(mfib(50))
1.23E-4
res14: Long = 12586269025
view raw memo3.scala hosted with ❤ by GitHub

Memoには標準でいくつかの実装が用意されおり、Memosに定義されています。

memo関数により自分で定義することもできます。

scala> val optionMemo = memo[Int, Int] { f =>
| var o = none[(Int, Int)]
| k => {
| o some {
| case (kk, vv) => (kk === k).fold(vv, f(k))
| } none {
| val v = f(k)
| o = (k, v).some
| v
| }
| }
| }
optionMemo: scalaz.Memo[Int,Int] = scalaz.Memos$$anon$3@1dd8a94
scala> val f = optionMemo { i =>
| Thread.sleep(1000)
| i |+| 100
| }
f: Int => Int = <function1>
scala> time(f(10))
1.002767
res44: Int = 110
scala> time(f(10))
0.001382
res45: Int = 110
scala> time(f(11))
1.000204
res46: Int = 111
view raw memo4.scala hosted with ❤ by GitHub

2011年12月17日土曜日

Python Iteratee

Python mini Hack-a-thon

参加しました。

今日はPythonでIterateeを書きました。

IterateeはIOストリームを抽象的に扱うもの・・・らしい。
composableでおもしろいなー
とちょっとした興味でさわってるのでそこまで詳しい訳じゃないです。

とりあえずソースコード。

class Maybe(object):
pass
Nothing = Maybe()
class Just(Maybe):
def __init__(self, value):
self.value = value
def __eq__(self, other):
return isinstance(other, Just) and other.value == self.value
def __str__(self):
return "Just({0})".format(self.value)
view raw maybe.py hosted with ❤ by GitHub

from functools import partial
from maybe import *
class Input(object):
def input(self, el, empty, eof):
if self == Empty:
return empty
elif self == EOF:
return eof
else:
return el(self)
class El(Input):
def __init__(self, e):
self.e = e
Empty = Input()
EOF = Input()
class IterV(object):
def bind_(self, i):
return self.bind(lambda _: i)
def file_lines(self, path):
f = open(path)
try:
return self._handle(f)
finally:
f.close()
class Done(IterV):
def __init__(self, a, i):
self.a = a
self.i = i
def enum(self, i):
return self
def run(self):
return self._maybe()
def _maybe(self):
return self.a
def bind(self, f):
return f(self.a)._bind(self.i)
def _bind(self, i):
return Done(self.a, i)
def _handle(self, f):
return self
class Cont(IterV):
def __init__(self, k):
self.k = k
def enum(self, i):
if len(i) == 0:
return self
else:
x = i[0]
xs = i[1:]
return self.k(El(x)).enum(xs)
def run(self):
return self.k(EOF)._maybe()
def _maybe(self):
raise Exception()
def bind(self, f):
return Cont(lambda i: self.k(i).bind(f))
def _bind(self, i):
return self.k(i)
def _handle(self, f):
line = f.readline()
if line:
return self.k(El(line))._handle(f)
else:
return self
def head():
def step(i):
return i.input(el = lambda el: Done(Just(el.e), Empty), empty = Cont(step), eof = Done(Nothing, EOF))
return Cont(step)
def peek():
def step(i):
return i.input(el = lambda el: Done(Just(el.e), el), empty = Cont(step), eof = Done(Nothing, EOF))
return Cont(step)
def drop(n):
if n == 0:
return Done((), Empty)
else:
def step(i):
return i.input(el = lambda _: drop(n - 1), empty = Cont(step), eof = Done((), EOF))
return Cont(step)
def length():
def step(acc, i):
return i.input(el = lambda _: Cont(partial(step, acc + 1)), empty = Cont(partial(step, acc)), eof = Done(acc, EOF))
return Cont(partial(step, 0))
view raw iteratee.py hosted with ❤ by GitHub

from unittest import TestCase, main
from iteratee import *
class IterateeTest(TestCase):
def test_input(self):
self.assertNotEqual(Empty, EOF)
def test_head(self):
self.assertEqual(head().enum([1, 2, 3]).run(), Just(1))
self.assertEqual(head().enum([]).run(), Nothing)
def test_peek(self):
self.assertEqual(peek().enum([1, 2, 3]).run(), Just(1))
self.assertEqual(peek().enum([]).run(), Nothing)
def test_drop(self):
self.assertEqual(drop(1).enum([1, 2, 3]).run(), ())
def test_length(self):
self.assertEqual(length().enum([1, 2, 3]).run(), 3)
self.assertEqual(length().enum([]).run(), 0)
def test_bind_(self):
self.assertEqual(drop(0).bind_(peek()).enum([1, 2, 3]).run(), Just(1))
self.assertEqual(drop(1).bind_(head()).enum([1, 2, 3]).run(), Just(2))
self.assertEqual(peek().bind_(peek()).enum([1, 2, 3]).run(), Just(1))
self.assertEqual(head().bind_(peek()).enum([1, 2, 3]).run(), Just(2))
def test_file_lines(self):
self.assertEqual(head().file_lines('test').run(), Just('hello\n'))
self.assertEqual(drop(2).bind_(head()).file_lines('test').run(), Just('python\n'))
self.assertEqual(drop(1).bind_(length()).file_lines('test').run(), 2)
if __name__ == '__main__':
main()

hello
world
python
view raw test hosted with ❤ by GitHub

これで何が嬉しいかというと
  • 処理が合成できる
  • IOストリームだけでなくリストなども処理できる
他にもハイパフォーマンスで型安全という特徴があるらしいのですが、この実装だと遅いし、Pythonだと型安全とか意味をなさないのであまり旨味がないかなあと思いました。

Traverse

Traverse

今日はなんだか複雑な型クラスTraverse。
Functorを継承しています。

traverseという関数をもちます。

case class ScalaChan[A](value: A)
implicit def ScalaChanEqual[A]: Equal[ScalaChan[A]] = equalA
implicit def ScalaChanShow[A]: Show[ScalaChan[A]] = showA
implicit lazy val ScalaChanTraverse: Traverse[ScalaChan] = new Traverse[ScalaChan] {
def traverse[F[_] : Applicative, A, B](f: A => F[B], t: ScalaChan[A]): F[ScalaChan[B]] = f(t.value).map(ScalaChan[B])
}
nel(1, 2, 3).traverse(_ +>: 1.some) assert_=== Some(NonEmptyList(2, 3, 4))
ScalaChan(10).traverse(_ +>: 1.wrapNel) assert_=== NonEmptyList(ScalaChan(10), ScalaChan(1))
1.some.traverse(_ +>: nel(1, 2, 3)) assert_=== NonEmptyList(Some(1), Some(1), Some(2), Some(3))
view raw traverse1.scala hosted with ❤ by GitHub

たぶんこれを見ても内部でどういったことをしているかわからないと思います。

sequence

Haskellのsequence関数を知っていますか?

sequence :: Monad m => [m a] -> m [a]
sequence ms = foldr k (return []) ms
where
k m m' = do { x <- m; xs <- m'; return (x:xs) }
view raw traverse2.hs hosted with ❤ by GitHub

Haskellのコードを見てもわからないのでScalaで書き直してみます。

def sequence[M[_]: Monad, A](xs: List[M[A]]): M[List[A]] = {
def k(m: M[A], n: => M[List[A]]): M[List[A]] = for {
x <- m
xs <- n
} yield x :: xs
xs.foldr(nil[A].pure[M])(k)
}
sequence(List(1.some, 2.some, 3.some)) assert_=== Some(List(1, 2, 3))
view raw traverse3.scala hosted with ❤ by GitHub

というかこれMonadである必要はなくね!?
と気付いた方、さすがです。
Applicativeで十分なので書き直してみます。

def sequence[M[_]: Applicative, A](xs: List[M[A]]): M[List[A]] = {
def k(m: M[A], n: => M[List[A]]): M[List[A]] = (m <**> n)(_ :: _)
xs.foldr(nil[A].pure[M])(k)
}
sequence(List(1.some, 2.some, 3.some)) assert_=== Some(List(1, 2, 3))
view raw traverse4.scala hosted with ❤ by GitHub

実はこのsequence関数はScalazでも定義されています。
これはより汎用的なものでListのみではなく、Traverseのインスタンスを持つものならば利用可能です。
そしてこの関数は、traverse関数に恒等関数を渡すことで実装できます。

sequence(List(1.some, 2.some, 3.some)) assert_=== List(1.some, 2.some, 3.some).sequence
List(1, 2, 3).some.sequence assert_=== List(1.some, 2.some, 3.some)
List(1, 2, 3).some.traverse(identity) assert_=== List(1, 2, 3).some.sequence
view raw traverse5.scala hosted with ❤ by GitHub

これらのことからtraverseはコンテナT[A]の要素Aを関数A => F[B]に適用してT[F[B]]になったものを畳み込み関数とApplicativeのapplyメソッドでF[T[B]]に変換する関数ということが・・・・・わかりにくいですよね、説明力なくてすみません・・・・・

実際には、畳み込み関数が使われているかどうかはTraverseのインスタンスの実装によって変わってきます。

Traverseの本質などは偉い人に聞いてもらうとして、ここではTraverseを使った関数を紹介します。

foldMapDefault

foldMapのTraverse実装。

nel(1, 2, 3).foldMapDefault(_.shows) assert_=== "123"
none[Int].foldMapDefault(_ |+| 100) assert_=== 0
view raw traverse6.scala hosted with ❤ by GitHub

collapse

sumのTraverse実装。

List(1, 2, 3).collapse assert_=== 6
none[String].collapse assert_=== ""
view raw traverse7.scala hosted with ❤ by GitHub

zipWithA

2つの値をコンテナにまとめてsequence。

nel(1, 2).zipWithA(nel("Hello", "World"))(_.shows |+| _ |> Option.apply) assert_=== Some(NonEmptyList(1Hello, 1World, 2Hello, 2World))
"a".some.zipWithA(1.some)((s, i) => s.parseInt.map(_ |+| i).toOption) assert_=== None
view raw traverse8.scala hosted with ❤ by GitHub

今回も説明がわかりにくくてごめんなさい。
ここで出てきたfoldr, foldMap, sumは近々書くので今日のところはこれでひとまずおわりです。

2011年12月15日木曜日

Empty, Each, Plus

小粒な型クラスその2

Empty

空を定義します。

<∅>

コンテナの型と要素の型を渡し、空のコンテナを返します。
∅が打ちにくい。

implicit lazy val IkamusumeEmpty: Empty[Ikamusume] = new Empty[Ikamusume] {
def empty[A]: Ikamusume[A] = Ikamusume[A]()
}
<∅>[List, Int] assert_=== nil[Int]
<∅>[Ikamusume, Int] assert_=== Ikamusume[Int]()
view raw empty1.scala hosted with ❤ by GitHub

Each

繰り返し処理を定義します。

foreach, |>|

関数を渡し、処理を繰り返します。
|>|はforeachのエイリアスです。

implicit lazy val IkamusumeEach: Each[Ikamusume] = new Each[Ikamusume] {
def each[A](e: Ikamusume[A], f: A => Unit): Unit = e.value.foreach(f)
}
Ikamusume(2, 3, 5, 7, 11).foreach(print)
Ikamusume(1, 1, 2, 3, 5) |>| print
scala> implicit lazy val IkamusumeEach: Each[Ikamusume] = new Each[Ikamusume] {
| def each[A](e: Ikamusume[A], f: A => Unit): Unit = e.value.foreach(f)
| }
IkamusumeEach: scalaz.Each[Ikamusume] = <lazy>
scala> Ikamusume(2, 3, 5, 7, 11).foreach(print)
235711
scala> Ikamusume(1, 1, 2, 3, 5) |>| print
11235
view raw each1.scala hosted with ❤ by GitHub

Plus

plusという2つの値を結合する関数を持つ。
Semigroupよりも、短絡評価ORの性質が強い。

<+>, <+>:

<+> は2つのコンテナを結合します。
<+>: は要素の型にPureのインスタンスが必要で、要素を渡して包み、結合します。

implicit lazy val IkamusumePlus: Plus[Ikamusume] = new Plus[Ikamusume] {
def plus[A](a1: Ikamusume[A], a2: => Ikamusume[A]): Ikamusume[A] = Ikamusume(a1.value ++ a2.value: _*)
}
Ikamusume('Scala) <+> Ikamusume('Scalaz) assert_=== Ikamusume('Scala, 'Scalaz)
nel(1, 2, 3) <+> nel(4, 5, 6) assert_=== NonEmptyList(1, 2, 3, 4, 5, 6)
1.some <+> 2.some assert_=== Some(1)
none <+> 1.some assert_=== Some(1)
"Scalaz".left[Int] <+> 100.right[String] assert_=== Right(100)
"Scalaz".left[Int] <+> "Scala".left[Int] assert_=== Left("Scalaz")
1 <+>: nel(2, 3) assert_=== NonEmptyList(1, 2, 3)
'a' <+>: 'z'.some assert_=== Some('a')
view raw plus1.scala hosted with ❤ by GitHub

今回紹介した型クラスは関数がそこまで多くないのであまり自分で定義することはないだろうけど、定義されたものを使う分にはとても便利です。

Length, Index

今日は小粒な型クラスを書いていきます。

Length

長さを定義します。

len

長さを返します。

case class Ikamusume[A](value: A*)
implicit def IkamusumeEqual[A]: Equal[Ikamusume[A]] = equalA
implicit def IkamusumeShow[A]: Show[Ikamusume[A]] = shows(Function.const("イカ娘"))
implicit lazy val IkamusumeLength: Length[Ikamusume] = new Length[Ikamusume] {
def len[A](a: Ikamusume[A]): Int = 10
}
List('a, 'b, 'c).len assert_=== 3
Ikamusume("ゲソ!").len assert_=== 10
view raw length1.scala hosted with ❤ by GitHub

Index

インデックスを定義します。

index, index_!, -!-

n番目の値を返します。
indexはOptionで返り、index_!はそのまま返ります。
-!-はindex_!のエイリアスです。

implicit lazy val IkamusumeIndex: Index[Ikamusume] = new Index[Ikamusume] {
def index[A](a: Ikamusume[A], i: Int): Option[A] = (i == 0).option(a.value)
}
Ikamusume(0)
nel('Scala, 'Scalaz).index(1) assert_=== Some('Scalaz)
nil[Int].index(2) assert_=== None
nel(3, 4, 6).index_!(0) assert_=== 3
'z'.some -!- 0 assert_=== 'z'
view raw index1.scala hosted with ❤ by GitHub

<--->

Length, Index, Equalのインスタンスがある場合に利用できます。
互いが内包する要素の間で、異なる要素の数を返します。

nel(1, 2, 3) <---> nel(1, 2, 3) assert_=== 0
nel(1, 2, 3) <---> nel(1, 2, 4) assert_=== 1
nel(1, 2, 3) <---> nel(4, 5, 6) assert_=== 3
nel(1, 2, 3) <---> nel(3, 2, 1) assert_=== 2
nel(1) <---> nel(1, 2, 3, 4, 5) assert_=== 4
1.some <---> none assert_=== 1
view raw index2.scala hosted with ❤ by GitHub

ペースを保つためその2へ続く。

2011年12月14日水曜日

Monad

朝、親に電車代を交渉し忘れて rpscala にいけないという・・・・・

今日はMonad。

Monad

Monadが何たるかは

モナドは象だ

を読みましょう!(まるなげ

モナドなんて高階関数を持ってて結合可能なコンテナぐらいの認識でいいのです!(ぼうろん

ここではScalazでMonadに関連する関数を紹介します。

Monadのインスタンスを直接定義するか、BindとPureのインスタンスが定義されていればimplicit parameterにMonadのインスタンスが供給されます。

case class ScalaChan[A](value: A)
implicit def ScalaChanEqual[A]: Equal[ScalaChan[A]] = equalA
implicit def ScalaChanShow[A]: Show[ScalaChan[A]] = showA
implicit lazy val ScalaChanPure: Pure[ScalaChan] = new Pure[ScalaChan] {
def pure[A](a: => A): ScalaChan[A] = ScalaChan(a)
}
implicit lazy val ScalaChanBind: Bind[ScalaChan] = new Bind[ScalaChan] {
def bind[A, B](a: ScalaChan[A], f: A => ScalaChan[B]): ScalaChan[B] = f(a.value)
}
def f[A[_]: Monad, B: Semigroup](a: A[B]) = for {
i <- a
j <- a
} yield i |+| j
f(100.some) assert_=== 200.some
f(ScalaChan("Scala")) assert_=== ScalaChan("ScalaScala")
implicit lazy val ScalaChanMonad: Monad[ScalaChan] = new Monad[ScalaChan] {
def pure[A](a: => A): ScalaChan[A] = ScalaChan(a)
def bind[A, B](a: ScalaChan[A], f: A => ScalaChan[B]): ScalaChan[B] = f(a.value)
}
view raw monad1.scala hosted with ❤ by GitHub

getOrElseM

値Mに包まれたOption[A]がSomeの場合、値を返し、Noneの場合呼び出し側を返します。

'Scalaz.wrapNel.getOrElseM('Scala.some.wrapNel) assert_=== NonEmptyList('Scala)
'Scalaz.wrapNel.getOrElseM(none.wrapNel) assert_=== NonEmptyList('Scalaz)
view raw monad2.scala hosted with ❤ by GitHub

ifM

trueの場合とfalseの場合で値を振り分けます。

true.some.ifM('Scalaz.some, 'Scala.some) assert_=== Option('Scalaz)
nel(false, true, false).ifM('イカちゃん.wrapNel, 'Scalaちゃん.wrapNel) assert_=== NonEmptyList('Scalaちゃん,'イカちゃん,'Scalaちゃん)
view raw monad3.scala hosted with ❤ by GitHub

replicateM

型パラメータを1つとる型と繰り返す回数を渡し、包まれた値を連結します。

'Z'.some.replicate[List](5) assert_=== List(Option('Z'), Option('Z'), Option('Z'), Option('Z'), Option('Z'))
'Z'.some.replicateM[List](3) assert_=== Option(List('Z', 'Z', 'Z'))
view raw monad4.scala hosted with ❤ by GitHub

foldLeftM, foldRightM

普通のfoldと違い、包まれた値を返す関数を渡します。

nel(1, 2, 3).foldLeftM(mzero[Int])(_ |+| _ |> (i => (i % 2 === 0).option(i)))
nel(1, 2, 3).foldLeftM(mzero[Int])(_.replicate[List](_)) assert_=== List(0, 0, 0, 0, 0, 0)
view raw monad5.scala hosted with ❤ by GitHub

Scalaではあるクラスを実装するのではなく、flatMapとmapさえ実装されていればfor式が使えちゃう。
for式はflatMapがネストしたら使えばいいんじゃなイカ?

2011年12月13日火曜日

Applicative, ApplicativeBuilder

#expertpython に行く予定でしたが池袋駅で目黒へ行くお金すらなかったことに気づいて泣く泣く帰ることに・・・・・
鬱々ですが明日も頑張ります。

今日はApplicative。

Applicative

ApplicativeはApplyとPointedを継承します。
基本的にApplyはFunctorや、Pureと組み合わせて使うのでApplicativeのインスタンスであるといろいろな関数が使えるようになります。

case class ScalaChan[A](value: A)
implicit def ScalaChanEqual[A]: Equal[ScalaChan[A]] = equalA
implicit def ScalaChanShow[A]: Show[ScalaChan[A]] = showA
implicit lazy val ScalaChanPure: Pure[ScalaChan] = new Pure[ScalaChan] {
def pure[A](a: => A): ScalaChan[A] = ScalaChan(a)
}
implicit lazy val ScalaChanFunctor: Functor[ScalaChan] = new Functor[ScalaChan] {
def fmap[A, B](a: ScalaChan[A], f: A => B): ScalaChan[B] = ScalaChan(f(a.value))
}
implicit lazy val ScalaChanBind: Bind[ScalaChan] = new Bind[ScalaChan] {
def bind[A, B](a: ScalaChan[A], f: A => ScalaChan[B]): ScalaChan[B] = f(a.value)
}
implicit lazy val ScalaChanApply: Apply[ScalaChan] = FunctorBindApply
def f[A[_]: Applicative, B](a: A[B], f: B => B => B) = a <*> (a map f)
f[Option, Int](5.some, a => b => a |+| b) assert_=== Option(10)
f[ScalaChan, String](ScalaChan("Scalaz"), a => b => a |+| b) assert_=== ScalaChan("ScalazScalaz")

Pointed

FunctorとPureを継承しています。
Applicative, Monadがこれを継承します。

Applicativeスタイル

forでは

lazy val f: Int => Int => Int = i => j => (i ∏) |+| (j ∏)
val a = for {
i <- 2.some
j <- 100.some
} yield f(i)(j)
val x = for {
i <- nel(1, 2, 3)
j <- nel(4, 5, 6)
} yield f(i)(j)

と書けますが、Applicativeスタイルでは

val b = 100.some <*> (2.some map f)
val y = nel(4, 5, 6) <*> (nel(1, 2, 3) map f)
a assert_=== b
x assert_=== y

と書けます。

この書き方では、関数がカリー化されている必要があります。
<**>, <***>, <****>, <*****>を使うとカリー化の必要がなくなり、適用の順番が綺麗に書けます。

def f(i: Int, j: Int): Int = (i ∏) |+| (j ∏)
val b = (2.some <**> 100.some)(f)
val y = (nel(1, 2, 3) <**> nel(4, 5, 6))(f)
a assert_=== b
x assert_=== y


ApplicativeBuilder

これらの書き方以外にApplicativeBuilderを使ったものがあります。

val c = (2.some |@| 100.some)(f)
a assert_=== c
def g(i: Int, j: Int, k: Int): Int = i |+| j |+| k
(1.some |@| 2.some |@| 3.some)(g) assert_=== Option(6)
(((_: Int) |+| 1) |@| ((_: Int) |+| 2) |@| ((_: Int) |+| 3))(g).apply(5) assert_=== 21

このようにApplicativeは値をコンテナから取り出して関数にてきようするものです。
for yieldであの形になったのなら、Applicativeスタイルで書けるということをおぼえておけばいいのだと思います。

2011年12月12日月曜日

NonEmptyList, Validation

昨日までMonadへ向けて型クラスをつらつら書いていましたが、Scalazのデータ構造にも触れたいと思います。

NonEmptyList

名の通りの空じゃないリストです。

利点は
  • head,tailで必ず値が返ることが保証される
  • reduceも必ず成功する・・・のだがそれにあたるメソッドはない。
と、これぐらいしか浮かばないけれど空を許さないという性質は意外と便利であったりします。

1.wrapNel assert_=== NonEmptyList(1)
nel(1, 2, 3) assert_=== NonEmptyList(1, 2, 3)
1 <:: 1.wrapNel assert_=== NonEmptyList(1, 1)
1.wrapNel :::> List(2, 3) assert_=== NonEmptyList(1, 2, 3)
List(1, 2) <::: 3.wrapNel assert_=== NonEmptyList(1, 2, 3)
1.wrapNel.list assert_=== List(1)
1.wrapNel.stream assert_=== Stream(1)
1.wrapNel.copure assert_=== 1
view raw nel.scala hosted with ❤ by GitHub

wrapNelは値をNonEmptyListで包みます。
nelはNonEmptyListのインスタンスを作ります。
<::は値を先頭に追加。
<:::, :::>はListをNonEmptyListに連結します。

ただ残念なところは、せっかくheadやtailが成功するのに、分解するためのunapply, unapplySeqが定義されていないことです。

ScalazではValidationと併せて使われます。

Validation

Validationはエラーか値を返すための直和型です。
Eitherとの違いはエラーをaccumulateできるところです。

解説、考察などは

http://d.hatena.ne.jp/xuwei/20110927/1317156625
http://d.hatena.ne.jp/cooldaemon/20111017/1318862426
http://d.hatena.ne.jp/terazzo/20111022/1319295098

に書いてあってあまり書くことない・・・

のでとりあえず関係するものを挙げていきます。

ValidationNEL

Validation[NonEmptyList[E], A]のエイリアスです。
Scalazオブジェクトに定義されています。

success, fail, successNel, failNel

Success, Failureで値を包みます。

1.success[String] assert_=== Success(1)
"Scala".fail[Int] assert_=== Failure("Scala")
implicit def ValidationNELEqual[E: Equal, A: Equal]: Equal[ValidationNEL[E, A]] = Equal.ValidationEqual[NonEmptyList[E], A]
implicit def ValidationNELShow[E: Show, A: Show]: Show[ValidationNEL[E, A]] = Show.ValidationShow[NonEmptyList[E], A]
'z'.successNel[Float] assert_=== Success('z')
'Scalaz.failNel[Long] assert_=== Failure(NonEmptyList('Scalaz))

parse{Boolean,Byte,Short,Int,Long,Float,Double}

StringWに定義されている関数。
パースに失敗したらNumberFormatExceptionをValidationで返します。

scala> sealed trait Error
defined trait Error
scala> case class NumberFormatError(e: NumberFormatException) extends Error
defined class NumberFormatError
scala> case class ArithmeticError(e: ArithmeticException) extends Error
defined class ArithmeticError
scala> def f(i: String, l: String): ValidationNEL[Error, Long] = try {
| (l.parseLong.liftFailNel <**> i.parseInt.liftFailNel)(_ / _).fail.map2(NumberFormatError).validation
| } catch {
| case e: ArithmeticException => ArithmeticError(e).failNel
| }
f: (i: String, l: String)scalaz.Scalaz.ValidationNEL[Error,Long]
scala> f("5", "100")
res3: scalaz.Scalaz.ValidationNEL[Error,Long] = Success(20)
scala> f("5", "1")
res4: scalaz.Scalaz.ValidationNEL[Error,Long] = Success(0)
scala> f("0", "a")
res5: scalaz.Scalaz.ValidationNEL[Error,Long] = Failure(NonEmptyList(NumberFormatError(java.lang.NumberFormatException: For input string: "a")))
scala> f("z", "a")
res6: scalaz.Scalaz.ValidationNEL[Error,Long] = Failure(NonEmptyList(NumberFormatError(java.lang.NumberFormatException: For input string: "a"), NumberFormatError(java.lang.NumberFormatException: For input string: "z")))
scala> f("0", "100")
res7: scalaz.Scalaz.ValidationNEL[Error,Long] = Failure(NonEmptyList(ArithmeticError(java.lang.ArithmeticException: / by zero)))

Validation#failはFailProjectionというError値を操作するためのコンテナを返します。
Eitherの場合はRightProjection, LeftProjectionとありますが、ValidationはデフォルトでSuccessに対して操作をするので、FailProjectionだけが存在します。
FailProjection#validationはもとのValidationを返します。


lift, liftFailNel

持ち上げ関数。
liftは値をwrap、liftFailNelはエラーをNonEmptyListでwrapします。

'Z'.success[String].lift[Option, Char] assert_=== Success(Option('Z'))
1.success[String].liftFailNel assert_=== 1.successNel

|, |||

| は失敗していたときに渡した値が返ります。getOrElseのようなもの。
||| は失敗していたときは、そのエラーの値をとり、成功時の型で値を返します。

100.success[String] | 50 assert_=== 100
"Scala".fail[Int] | 50 assert_=== 50
"Scalaz".fail[Int] ||| (_.size) assert_=== 6

Validation、とってもいいですよ!
最近、エラー処理を書いてはいけないというスライドが上がっていました。
アレほど強力ではないですが、エラーをaccumulateしていけるということはやはり便利だと思います。

2011年12月11日日曜日

Apply

一昨日の分書いてない、昨日の分書いてない、今日の分書いてない・・・・・
そしてどんどん難しくなっていくScalazネタ。
実際危ない!

Apply

Applyは名の通り適用のための型クラスです。
しかし、ただ関数に値を適用するものではなく、コンテナ内の関数にコンテナ内の値を適用します。

case class ScalaChan[A](value: A)
implicit def ScalaChanEqual[A]: Equal[ScalaChan[A]] = equalA
implicit def ScalaChanShow[A]: Show[ScalaChan[A]] = showA
implicit lazy val ScalaChanFunctor: Functor[ScalaChan] = new Functor[ScalaChan] {
def fmap[A, B](a: ScalaChan[A], f: A => B): ScalaChan[B] = ScalaChan(f(a.value))
}
implicit lazy val ScalaChanBind: Bind[ScalaChan] = new Bind[ScalaChan] {
def bind[A, B](a: ScalaChan[A], f: A => ScalaChan[B]): ScalaChan[B] = f(a.value)
}
implicit lazy val ScalaChanApply: Apply[ScalaChan] = FunctorBindApply
ScalaChan(100) <*> ScalaChan((_: Int) + 100) assert_=== ScalaChan(200)
view raw apply1.scala hosted with ❤ by GitHub

FunctorBindApplyはApplysに定義されています。
FunctorとBindを暗黙的にとり、Applyを返します。

<*>, <**>, <***>, <****>, <*****>

Functorではmap、Bindでは>>=と代表する関数がありますが、Applyでは<*>です。
これは<*>の場合は先程の例の通りですが、<**>からはコンテナと関数、implicit parameterにFunctorをとります。
*が増えるごとに、コンテナの数、関数の引数が増えていきます。
ただし、値がNilやNone, Leftなどが含まれている場合はその値が返ります。

"Scala".some <*> ((_: String) |+| "ちゃんかわいい").some assert_=== "Scalaちゃんかわいい".some
("Scala".some <**> none)(_ |+| _) assert_=== none
(3.right[String] <***> ("4".left, 6.right))(_ |+| _ |+| _) assert_=== "4".left
view raw apply2.scala hosted with ❤ by GitHub

<|*|>, <|**|>, <|***|>, <|****|>

コンテナをわたし、コンテナに包まれたタプルを返します。
ただし、値がNilやNone, Leftなどが含まれている場合はその値が返ります。

List("Scalaちゃん") <|*|> List("イカ娘") assert_=== List(("Scalaちゃん", "イカ娘"))
List("Scala") <|**|> (nil[String], List("Scalaz")) assert_=== nil
'a'.right[Int] <|***|> ('b'.right[Int], 'c'.right[Int], 'd'.right[Int]) assert_=== ('a', 'b', 'c', 'd').right[Int]
view raw apply3.scala hosted with ❤ by GitHub

*>, <*

>, <が指す値を返します。
ただし、値がNilやNone, Leftなどが含まれている場合はその値が返ります。

1.some <* 10.some assert_=== 1.some
none[Int] *> 10.some assert_=== none
1.right[String] *> 10.right[String] assert_=== 10.right[String]
1.right[String] <* "10".left[Int] assert_=== "10".left[Int]
view raw apply4.scala hosted with ❤ by GitHub

コピーアンドペースト重点。

これらの関数は型により動作が変わりますが、大体の型はこのような動きをします。

第二回Scala会議

第二回Scala会議に参加し、Scalazについて発表しました。

資料
http://halcat0x15a.github.com/slide/scala_kaigi/out/index.html


いつも通り緊張で死にそうになりながらみずしまさんとゆろよろさんに助けられつつの発表でした。
たまきさんの気遣いにも感謝です。

自分の発表能力はまだまだ低く、もっと練習して行かなければいけないと感じます。

懇親会では技術的な話をたくさん聴けて楽しかったです。
いつも支払いをしていただいて、 高校生な自分としては本当に助かります。
技術的なアウトプットを増やしていって、少しでも応えられたらなと思います。

2011年12月8日木曜日

Bind

昨日は rpscala へ行ってきました。
直接感想等をもらえてうれしかったです。
いつも御世話になっている皆さんに少しでも役に立つようがんばります。

Bind

今日はBindです。
Bindは型Z[_]を型パラメータにとり、型Z[A]と関数A => Z[B]を受け取り、Z[B]を返す関数bindを持ちます。
Haskellでは>>=にあたります。

case class ScalaChan[A](value: A)
implicit def ScalaChanEqual[A]: Equal[ScalaChan[A]] = equalA
implicit def ScalaChanShow[A]: Show[ScalaChan[A]] = showA
implicit lazy val ScalaChanFunctor: Functor[ScalaChan] = new Functor[ScalaChan] {
def fmap[A, B](a: ScalaChan[A], f: A => B): ScalaChan[B] = ScalaChan(f(a.value))
}
implicit lazy val ScalaChanBind: Bind[ScalaChan] = new Bind[ScalaChan] {
def bind[A, B](a: ScalaChan[A], f: A => ScalaChan[B]): ScalaChan[B] = f(a.value)
}
lazy val scalaChan = for {
i <- ScalaChan(7)
s <- ScalaChan("Scalaz")
} yield s |+| i.shows
scalaChan assert_=== ScalaChan("Scalaz7")
view raw bind1.scala hosted with ❤ by GitHub

この例ではScalaChanFunctorとScalaChanBindを定義し、 MAに定義されたmap,flatMapが使えるようになったかを確認しました。

flatMap, >>=, >>=|, >|>

flatMapと>>=は同じ関数です。
>>=|と>|>も同じ関数です。
>>=|, >|> はflatMap, >>=と違い、内包していた値を捨て、値だけを渡します。

List.fill(2, 2)(100).flatMap(1 +>: _) assert_=== List(1, 100, 100, 1, 100, 100)
(1.some.pure[Option] >>= (1 +>: _)) assert_=== 2.some
1.some.fpure[List] >>=| 2.some assert_=== 2.some
1.pure[Tuple1].fpure[List].fpure[Option] >|> none[Int].pure[Tuple1] assert_=== Tuple1(None)
view raw bind2.scala hosted with ❤ by GitHub

ちなみにflatMap, >>=の糖衣関数∗、>>=|, >|>の糖衣関数∗|が定義されています。

forever

使い方がよく分からない関数。
>|> を使い、foreverの結果を連結し続けます。
なので評価するとStackOverflowError必至だと思うのですが・・・

scala> try { ((_: Int) + 1).forever[Int].apply(1) } catch { case e => e }
res75: Any = java.lang.StackOverflowError
scala> try { 1.pure[Stream].forever[Stream[Int]] } catch { case e => e }
res76: java.lang.Object = java.lang.StackOverflowError
view raw bind3.scala hosted with ❤ by GitHub

join

型M[A]のAに、M[A]が適用されたM[M[A]]を連結し、M[A]を返します。
要は汎用的flatten。
糖衣関数にμがあります。

List(3, 4, 6).replicate[List](2).join assert_=== List(3, 4, 6, 3, 4, 6)
lazy val f: Int => Int => Int = i => j => i |+| j
(f μ).apply(5) assert_=== 10
view raw bind4.scala hosted with ❤ by GitHub

最後の例はjoinを行ったことにより、

(\a. (\b. a + b))




(\a. (\b. b)(a) + a)

に変換されました。

値を適用すると、

(\a. (\b. a + b))(5)(5) ->
(\b. 5 + b)(5) ->
5 + 5 -> 10

(\a. (\b. b)(a) + a)(5)
(\b. b)(5) + 5
5 + 5 -> 10

となり、関数に値を2度適用する関数であることが分かります。

Bindはbindという1つの関数だけを持っていますが、それを定義するだけでこれだけのものが使えるようになります。

Scalazおそるべし・・・・!


2011年12月7日水曜日

Functor

Pure, Functor, Pointed, Apply, Applicative, Bindを倒さないとMonadへはたどり着けない・・・・・

ということでFunctorの紹介。

Functor

Pureと同じように型パラメータを1つとる型を型パラメータにとります。

fmapというコレクションでおなじみのmapと似た関数を持っています。

mapと違うところは要素を包む型が多相であるというところです。

case class Ikamusume[A](value: A)
implicit def IkamusumeEqual[A]: Equal[Ikamusume[A]] = equalA
implicit def IkamusumeShow[A]: Show[Ikamusume[A]] = showA
implicit def IkamusumeFunctor: Functor[Ikamusume] = new Functor[Ikamusume] {
def fmap[A, B](r: Ikamusume[A], f: A => B): Ikamusume[B] = Ikamusume(f(r.value))
}
def mapAppend[M[_]: Functor, A: Semigroup](m: M[A], a: A) = m.map(_ |+| a)
mapAppend(List(1, 2, 4), 2) assert_=== List(3, 4, 6)
mapAppend(Ikamusume(100), 1) assert_=== Ikamusume(101)
view raw functor1.scala hosted with ❤ by GitHub

Identity

mapply

値を内包された関数に適用します。

1.mapply((1 |+| (_: Int)).some) assert_=== 2.some
List(1).mapply(List(1 +>: (_: List[Int]), (_: List[Int]) |+| List(1, 1))) assert_=== List(List(1, 1), List(1, 1, 1))
view raw functor3.scala hosted with ❤ by GitHub

MA

map, map2, >|

mapは関数を渡し、内包する値に適用します。
map2はFunctorがネストしている場合に利用でき、ma.map(_.map(f))と等価です。
>| は値を渡し、その値で塗りつぶします。

(1, 2).map(1 +) assert_=== (1, 3)
((_: Int) + 1).map(2 *).apply(5) assert_=== 12
List(1.some, 2.some, 4.some).map2[Option, Int, Int](2 +) assert_=== List(3.some, 4.some, 6.some)
List(List(1, 2, 3), List(2, 2, 2)).map2[List, Int, Int](2 *) assert_=== List(2.replicate[List](3, _ |+| 2), 4.replicate[List](3))
1.replicate[Stream](5) >| 3 assert_=== 3.replicate[Stream](5)
view raw functor2.scala hosted with ❤ by GitHub

fpair, fpure

fpairは内包された値のペアを作ります。
fpureは内包された値を指定した型で包みます。

1.some.fpair assert_=== Some((1, 1))
List(1, 2, 3).fpair assert_=== List((1,1), (2,2), (3,3))
1.some.fpure[List] assert_=== Some(List(1))
List(1, 2, 3).fpure[Option] assert_=== List(Some(1), Some(2), Some(3))
view raw functor4.scala hosted with ❤ by GitHub

comp

Option[List[Int]]をMA[M[_], A]とみなすとき、MにOptionが、AにList[Int]が適用されMA[Option, List[Int]]となります。
compではMにOption[List[_]]を、AにIntを適用したMA[({ type X[A] = Option[List[A]] })#X, Int]を返します。
MAの型としては型の部分適用されたものが返るので普通の型クラスは対応していません。
しかしCompをインポートすることでApplicativeとFunctorのimplicit valueを得ることができます。

import Comp._
List.fill(2, 2)(1).comp.map(10 *) assert_=== List.fill(2, 2)(10)
List(1).some.comp.fpure[Option] assert_=== List(1.some).some
Ikamusume(100).some.comp.map(2 *) assert_=== Ikamusume(200).some
view raw functor5.scala hosted with ❤ by GitHub

InvariantFunctor

FunctorはInvatiantFunctorを継承しています。 

MA

xmap

一度別の型に変換し、また元の型へ変換します。

("Hello" |+| "World")(Semigroup.IntSemigroup.xmap(_.shows)(_.size)) assert_=== "10"
(1 |+| 1)(Semigroup.StringSemigroup.xmap(_.toInt)(_.shows)) assert_=== 11

Semigroup以外に、Endo, Monoid, Memoのインスタンスが定義されています。

xmapはともかく、mapやmap2,compは使いどころが多いと思います。
積極的に使っていってコードをScalazで染め上げましょう!

2011年12月6日火曜日

Pure

Scalazはモナモナしたデータ構造が多いので早くMonadところまでやりたい・・・

ということで今日はPureを書きます。

Pure

Pureは"型パラメータを1つとる型"を型パラメータにとり、値を包み込む関数を持ちます。

分かりにくいので例を挙げます。

case class ScalaChan[A](value: A)
implicit def ScalaChanEqual[A]: Equal[ScalaChan[A]] = equalA
implicit def ScalaChanShow[A]: Show[ScalaChan[A]] = showA
implicit def ScalaChanPure = new Pure[ScalaChan] {
def pure[A](a: => A) = ScalaChan(a)
}
"Scalaちゃん".pure[ScalaChan] assert_=== ScalaChan("Scalaちゃん")
view raw pure1.scala hosted with ❤ by GitHub

Pureを利用した関数では、計算をして結果を包むものが多いです。

pure

型を渡し、値をその型で包みます。

1.pure[List] assert_=== List(1)
"Scalaz".pure[Option] assert_=== "Scalaz".some
'Scalaz.pure[Function0] assert_=== (() => 'Scalaz)
view raw pure2.scala hosted with ❤ by GitHub

iterate, repeat, replicate

iterate, repeatは無限リストなんかを作る関数。
Stream以外に使えるものはあるのだろうか?

replicateはiterate, repeatと似ているけれど、大きさが決まっています。
これはListなどでも使えます。

1.iterate[Stream](1 +).take(3) assert_=== Stream(1, 2, 3)
1.repeat[Stream].take(3) assert_=== Stream(1, 1, 1)
1.replicate[List](3) assert_=== List(1, 1, 1)
lazy val nextPrime: Int => Int = _.doWhile(1 +, i => (2 until i).any(i % _ == 0))
2.iterate[Stream](nextPrime).take(5) assert_=== Stream(2, 3, 5, 7, 11)
2.replicate[List](5, nextPrime) assert_=== List(2, 3, 5, 7, 11)
2.replicate[Option](3) assert_=== 6.some
view raw pure3.scala hosted with ❤ by GitHub

+>:

値を包み込み、結合する演算子。
使い方がよくわからず、 List(1).+>:(1) とか書いてたけど : がついてるとレシーバが右にくるとの御指摘が。
演算子の結合順位もよくわかっていないのでコップ本を読み直さないとですね・・・

1 +>: List(1) assert_=== List(1, 1)
1 +>: 1.some assert_=== 2.some
(1 +>: ((_: Int) + 1)).apply(1) assert_=== 3
view raw pure4.scala hosted with ❤ by GitHub

MA

今回の関数は +>: 以外Identityに定義されています。
+>: はどこに定義されているのかというと、MAに定義されています。

MAは"型パラメータを1つとる型"Mと型Aを型パラメータにとります。

scala> (nil[Int]: MA[List, Int])
res65: scalaz.MA[List,Int] = scalaz.MAs$$anon$3@1d45221
scala> (none[String]: MA[Option, String])
res66: scalaz.MA[Option,String] = scalaz.MAsLow$$anon$1@90cae4
view raw ma.scala hosted with ❤ by GitHub

Scalaではイレイジャで型M[A]の型Aが消えてしまうため、このような定義になっています。

このMAでは、"型パラメータを1つとる型"を対象にした型クラスを利用する関数が定義されています。

今後紹介する関数では、Identity,MAそしてMABで定義されたものを中心に紹介していきます。

これらはScalaz特有の関数を利用するための型クラスなので深い理解はいりませんが、Scalazを使う上で覚えておいて損はないでしょう。

2011年12月4日日曜日

Semigroup, Zero, Monoid

今日はSemigroupでゲソ!

この記事は

Functional Ikamusume Advent Calendar jp 2011



一人Scalaz Advent Calendar

を兼ねているんじゃなイカ!?


Semigroup

Semigroupは結合可能という性質を表すでゲソ。

Semigroupは関数 def append(s1: S, s2: => S): S を持ち、2つの値から一つの結果を得る関数を持つでゲソ。

Semigroupのインスタンスはsemigroup関数を使うことで定義できるんじゃなイカ?

Semigroups#semigroup

case class Ikamusume(syokusyu: Int = 10)
implicit def IkamusumeEqual: Equal[Ikamusume] = equalA
implicit def IkamusumeShow: Show[Ikamusume] = shows("ゲソ" * _.syokusyu)
implicit def IkamusumeSemigroup: Semigroup[Ikamusume] = semigroup(_.syokusyu + _.syokusyu |> Ikamusume)
(Ikamusume() |+| Ikamusume()).shows assert_=== "ゲソゲソゲソゲソゲソゲソゲソゲソゲソゲソゲソゲソゲソゲソゲソゲソゲソゲソゲソゲソ"

Semigroupを利用する関数

|+|

加算だけでなく、型によって様々な動きをするでゲソ。

1 |+| 1 assert_=== 2
List(1) |+| List(1) assert_=== List(1, 1)
"Hello" |+| "World" assert_=== "HelloWorld"
1.some |+| 1.some assert_=== 2.some
false |+| true assert_=== true

加算や連結、論理和のような動きをするでゲソ。
===と同様に型安全でもあるでゲソ!

・・・・・Semigroup単体だとこれだけでゲソ。

あまりにも寂しいのでZero, Monoidまでやろうじゃなイカ!

Zero

Zeroは単位元を表すでゲソ。

mzero

mzeroは型パラメータを取り、その型の単位元を返すでゲソ。
mzero[Int] assert_=== 0
mzero[String] assert_=== ""
mzero[List[Int]] assert_=== nil[Int]
mzero[Option[Int]] assert_=== none[Int]
view raw zero1.scala hosted with ❤ by GitHub

matchOrZero

matchOrZeroは型パラメータとPartialFunctionを取り、マッチしない場合はその型の単位元を返すでゲソ!

lazy val geso: Option[Int] => String = _.matchOrZero {
case Some(n) => "ゲソ" * n
}
geso(2.some) assert_=== "ゲソゲソ"
geso(none) assert_=== ""
view raw zero3.scala hosted with ❤ by GitHub

Zeros#zero

Zeroのインスタンスはzeroにより定義できるんじゃなイカ?

implicit def IkamusumeZero: Zero[Ikamusume] = zero(Ikamusume(0))
mzero[Ikamusume].shows assert_=== ""
view raw zero2.scala hosted with ❤ by GitHub

そして、SemigroupとZeroを兼ね備えたものがMonoidなのでゲソ!

Monoid

MonoidはSemigroupとZeroを継承したものでゲソ。

Monoidは

forall a. append(zero, a) == a

forall a. append(a, zero) == a

を満たすのでゲソ。

def check[A: Equal: Show: Monoid](a: A) = {
a |+| mzero[A] assert_=== a
mzero[A] |+| a assert_=== a
}
check(1)
check("Scalaz")
check(List(1, 2, 3))
check(Ikamusume())
view raw monoid1.scala hosted with ❤ by GitHub

イカ娘も立派なモノイドじゃなイカ?

Monoid単体を利用する関数はほとんどないのでゲソ。
Monoidは他の型クラスと一緒に使うことが多いのでその時に紹介しようじゃなイカ!

Order, Ordering

OrderOrderingについて。

OrderはEqualを継承しており、比較を可能にします。

Scala標準のAPIにもOrdered, Orderingがありますが、これらはJavaのComparableのように正、零、負で表しています。

しかし、このOrderでは比較結果をOrderingという型で返します。

?|?

比較結果を得るもの。
compareToみたいなもの。

1 ?|? 1 assert_=== EQ
1 ?|? 2 assert_=== LT
2 ?|? 1 assert_=== GT
"Scalaz" ?|? "Scala" assert_=== GT
List(2, 4) ?|? List(3, 5) assert_=== LT
view raw order1.scala hosted with ❤ by GitHub

これらがそれぞれequal, less than, greater thanを表しています。

これが素晴らしいところはOrderingがモノイドであること。

これにより、優先順位の高い比較結果から順に結合していくことで適切な比較結果を得られます。

(1 ?|? 1) |+| (1 ?|? 1) |+| (1 ?|? 1) assert_=== EQ
(1 ?|? 1) |+| (1 ?|? 2) |+| (2 ?|? 1) assert_=== LT
(1 ?|? 1) |+| (2 ?|? 1) |+| (1 ?|? 2) assert_=== GT
view raw order5.scala hosted with ❤ by GitHub

比較結果モノイドについては、 比較はモノイド の記事が面白いので是非見て下さい。

lt, gt, lte, gte

比較する関数です。
標準のものと違うところは型安全なところと、記号じゃないから括弧で括らないといけないところ。

assert(1 lt 2)
assert(2 gt 1)
assert("Scalaz" gt "Scala")
assert(List(2, 4) lt List(3, 5))
view raw order2.scala hosted with ❤ by GitHub

max, min

2値の間で最大、最小を得る関数。

1 max 1 assert_=== 1
1 max 2 assert_=== 2
2 min 1 assert_=== 1
Identity("Scala") max "Scalaz" assert_=== "Scalaz"
Identity(List(2, 4)) min List(3, 5) assert_=== List(2, 4)
view raw order3.scala hosted with ❤ by GitHub

Orders

order, orderBy

Orderのインスタンスを作ります。
orderは2つの値を取り比較結果を返す関数を渡します。
orderByは値を取り、比較可能な値を返す関数を渡します。

case class Ikamusume(syokusyu: Int)
implicit def IkamusumeOrder: Order[Ikamusume] = order(_.syokusyu ?|? _.syokusyu)
implicit def IkamusumeOrder: Order[Ikamusume] = orderBy(_.syokusyu)
Ikamusume(10) ?|? Ikamusume(100) assert_=== LT
view raw order4.scala hosted with ❤ by GitHub

scala標準のOrderingも暗黙の型変換でOrderのインスタンスを得ることができます。

比較する際はjava.lang.Comparable, scala.math.Orderingよりもscalaz.Orderの検討を!

2011年12月3日土曜日

Show

今日はShowについて。

Showは表示可能という性質を与えます。

インスタンスは普通にnewで作ることもできますが、Showsに定義された関数を使っていきましょう。

Shows

case class ScalaChan(name: String = "Scalaちゃん")
implicit def ScalaChanShow: Show[ScalaChan] = show(_.name.toList)
implicit def ScalaChanShow: Show[ScalaChan] = shows(_.name)
ScalaChan().shows assert_=== "Scalaちゃん"
case class Ikamusume() { override def toString = "イカちゃん" }
implicit def IkamusumeShow: Show[Ikamusume] = showA
Ikamusume().shows assert_=== "イカちゃん"
implicit def SomeShow[A: Show]: Show[Some[A]] = showBy(s => (s: Option[A]))
Some(1).shows assert_=== "Some(1)"
view raw show1.scala hosted with ❤ by GitHub

showは値を受け取り、List[Char]を返す関数を渡します。
文字列ではなく、List[Char]なのはHaskellをリスペクトしてるからでしょうか?
文字列に対してはtoListなどを呼ばないといけません。

それに対してshowsはStringを返す関数を渡せばいいので、こちらを使うことが多いと思います。

showAはShowをtoStringにより実装します。
case classなどはこれでいいかもしれません。

showByは値を取り、Showのインスタンスを持つ型を返す関数を渡します。

基本的にはshowAとshowsを使っていきましょう。

Showを使う関数

show
shows

Showで定義した文字列を取得する関数。
toStringとは違い、表示できることが保証されています(大抵の場合、"A@17d577c"などの文字列は返らない)。

"Scalaz".show assert_=== List('S', 'c', 'a', 'l', 'a', 'z')
"Scalaz".shows assert_=== "Scalaz"
346.shows assert_=== "346"
view raw show2.scala hosted with ❤ by GitHub

print
println

名前通りの関数。
rpscalaで初めて気がついた。

scala> 1.print
1
scala> "Scalaz".println
Scalaz
view raw show3.scala hosted with ❤ by GitHub

text

scala.xml.Textを返す関数・・・・・需要あるの?
scala.xml.Elemのインスタンスはデフォルトでは存在しない模様。
こっちの方が重大じゃなイカ。

implicit def ElemShow: Show[xml.Elem] = showA
<scala>{ "Scalaちゃん".text }</scala> assert_=== <scala>Scalaちゃん</scala>
view raw show4.scala hosted with ❤ by GitHub

これらの関数と昨日紹介したassert_===など。
他にもLoggerやWriterに関係するものがあったりするけどまた今度。

2011年12月2日金曜日

Equal

Equalは型クラスです。
型クラスについては10日にやるScala会議で話す資料とか水島さんの死霊とか。

この型クラスは等しいという性質を与えます。

作り方

case class ScalaChan()
implicit def ScalaChanEqual: Equal[ScalaChan] = new Equal[ScalaChan] {
def equal(a1: ScalaChan, a2: ScalaChan): Boolean = a1 == a2
}
implicit def ScalaChanEqual: Equal[ScalaChan] = equal(_ == _)
implicit def ScalaChanEqual: Equal[ScalaChan] = equalA
assert(ScalaChan() === ScalaChan())
view raw e1.scala hosted with ❤ by GitHub

最初の方法はEqualのインスタンスを直接作るというもの。
二番目の方法はequalを使う方法。
equalは2つの値を受け取り、Booleanを返す述語を渡す。
三番目のequalAはequalをAnyの==を使って実装するというもの。
equalAとequalはEqualsに定義されており、Scalazがそれを継承しています。
この3つはどれも同じEqual[ScalaChan]が作られます。

Eqaulを利用した関数

===
/==

見た目通り等しい、等しくないを返す関数。
標準の==,!=と違うところは型安全というところ。

scala> 1 === 1
res39: Boolean = true
scala> 1 /== 1
res41: Boolean = false
scala> 1 /== 1L
<console>:23: error: type mismatch;
found : Long(1L)
required: Int
1 /== 1L
^
view raw e2.scala hosted with ❤ by GitHub

糖衣関数?もある。

assert("Scalaz" ≟ "Scalaz")
assert("Scalaちゃん" ≠ "Scalaz")
view raw e3.scala hosted with ❤ by GitHub

Equalだけを利用した関数が少なすぎて物悲しいのでもう一個

assert_===

Unit TestライブラリによくあるassertEqual的なもの。
エラーメッセージがちょっとかっこいい。
この関数は値がEqualの他にShowのインスタンスを持つことが必要です。

scala> "Scalaz" assert_=== "Scalaz"
scala> "Scalaちゃん" assert_=== "Scalaz"
java.lang.RuntimeException: Scalaちゃん ≠ Scalaz
at scalaz.Scalaz$.error_(Scalaz.scala:100)
at scalaz.Identity$class.assert_$eq$eq$eq(Identity.scala:32)
at scalaz.Identity$$anon$1.assert_$eq$eq$eq(Identity.scala:169)
.
.
.
.
scala> "Scalaちゃん" assert_≟ "Scalaちゃん"
view raw e4.scala hosted with ❤ by GitHub

基本的なEqualのインスタンスはEqualのコンパニオンオブジェクトに定義されています。
自分で定義したclassはequalやequalAでインスタンスを作っておきましょう。

Identity

一人Scalaz Advent Calendar

初日ということでIdentityから。

Identityの説明だけれど型クラスに関連するもの(===とか|+|とかほとんどの関数)やScalazのデータ構造(Validation,LazyTupleなど)に関するものは取り扱わないです。
後日EqualやSemigroup,Validationなどを説明するときに出てきます。

Identityは型パラメータAをとり、def value: Aという未定義の関数を持ちます。
パラメータAに様々な関数を提供するコンテナと考えてよいでしょう。


Identitys

IdentitysのmkIdentityによって全ての値はIdentityに暗黙の型変換することができます。
また、unMkIdentityによりIdentityをもとの値に戻すことも可能です。

val i: Identity[Int] = 1
val a: Int = i
view raw i1.scala hosted with ❤ by GitHub

unitalという謎のIdentity[Unit]が定義されているけど何に利用するかは不明。


Identity

??


簡単に言うとnullチェック。
nullだった場合は引数で与えた値が返る。

"Scalaz" ?? "Scalaちゃん" assert_=== "Scalaz"
(null: String) ?? "Scalaちゃん" assert_=== "Scalaちゃん"
view raw i2.scala hosted with ❤ by GitHub

|>

関数に呼び出し側の値を適用する関数。
ちょっと意味がわからない、コードを見ましょう。

1 |> (_ + 1) assert_=== 2
1 |> Option.apply assert_=== Some(1)
view raw i3.scala hosted with ❤ by GitHub

some, left, right, pair, squared

ある型に包む関数。
pairとsquaredは値のペアをタプルで返す。
def squared = pairみたいな定義だけどいるんですかこれ。

1.some assert_=== Some(1)
1.right[String] assert_=== Right(1)
"Scalaちゃん".left[Int] assert_=== Left("Scalaちゃん")
"ゲソ".pair.assert_===(("ゲソ", "ゲソ"))
"ゲソ".pair assert_=== "ゲソ".squared
view raw i4.scala hosted with ❤ by GitHub

doWhile, whileDo

名前通りの関数。
関数と述語を渡す。

1.whileDo(_ + 1, _ < 10) assert_=== 10
"Scala".doWhile({ s => println(s); readLine }, _ != "Scalaz") assert_=== "Scalaz"
view raw i5.scala hosted with ❤ by GitHub

Scalazの型クラス、データ構造に関するものを抜くとこれだけ。

これだけではScalazの便利さがわからないと思うので、ぜひ続きも見て下さい!

2011年9月6日火曜日

ScalazでIteratee その2

前の続き。

実際にファイルを読み込めるようにしました。

type EnumeratorM[E, M[_], A] = IterV[E, A] => M[IterV[E, A]]
def enumReader[A](r: BufferedReader): EnumeratorM[String, IO, A] = { iter =>
def loop: EnumeratorM[String, IO, A] = {
case i @ Done(_, _) => (i: IterV[String, A]).pure[IO]
case i @ Cont(k) => for {
o <- rReadLn(r)
i <- o match {
case None => i.pure[IO]
case Some(s) => s.pure[IO] >>= loop.compose(k.compose(El(_)))
}
} yield i
}
loop(iter)
}
def enumFile[A](f: File): EnumeratorM[String, IO, A] = i => bufferFile(f).bracket(closeReader)(enumReader[A](_)(i))
view raw f.scala hosted with ❤ by GitHub

EnumeratorMはIterVをモナドで包むための型です。

enumReaderはブログの例とは違いますが、一字ずつ読み込むのではなく、BufferReaderを用いて一行づつ読み込むようにしています。
<<<はScalazで定義されており、composeと同じです。
enumと同様に、Doneになるまで処理を繰り返します。

enumFileはファイルをenumReaderに渡す。
bracketにより、closeReaderが確実に行われることが保証されています。

実行例
val file = new File("src/main/resources/test.txt")
file.exists assert_=== true
def g[A](i: IterV[String, A]) = run(enumFile(file)(i).unsafePerformIO)
g(length) assert_=== Some(1)
g(peek[String] >|> head[String]) assert_=== Some(Some("hello"))
view raw g.scala hosted with ❤ by GitHub
hello
view raw test.txt hosted with ❤ by GitHub

現在、scalaz.effectsにあるIterateeな入出力関数はこれらと、標準入力からの読み込みだけです。

2011年9月4日日曜日

ScalazでIteratee

Scala会議でLTしてきました。


拙い発表でしたが、まじめに聞いてくれたScala会議参加者の方々には感謝です。
このLTで話せなかったIterateeについて、tanakhさんのブログを参考に書かせていただきます。

Scalazでの実装

ブログを参考に実際に実装してみます。

sealed trait StreamG[+E]
case object Empty extends StreamG[Nothing]
case class El[E](el: E) extends StreamG[E]
case object EOF extends StreamG[Nothing]
sealed trait IterV[+E, +A]
case class Done[E, A](x: A, str: StreamG[E]) extends IterV[E, A]
case class Cont[E, A](k: StreamG[E] => IterV[E, A]) extends IterV[E, A]
view raw a.scala hosted with ❤ by GitHub


定義は簡単。
Haskellのコードとあまり変わりがないですね。(ぇ
ストリームはList(El(1), El(2), El(3), EOF())みたいなイメージです。

def enum[E, A]: (IterV[E, A], List[E]) => IterV[E, A] = {
case (i, Nil) => i
case (i@Done(_, _), _) => i
case (Cont(k), x :: xs) => enum(k(El(x)), xs)
}
def run[E, A]: IterV[E, A] => Option[A] = {
case Done(x, _) => Some(x)
case Cont(k) => k(EOF) match {
case Done(x, _) => Some(x)
case _ => None
}
}
view raw b.scala hosted with ❤ by GitHub


enum,runの実装。
enumはfoldl(むしろreduce?)そのままで、IterVを関数と初期値にみたたて、Doneの場合でも結果を返すものと思えばいいです。
runは結果を取り出すだけ。初期値に当たるものがない場合があるので、結果はOptionで返します。

def head[E]: IterV[E, Option[E]] = {
def step: StreamG[E] => IterV[E, Option[E]] = {
case El(el) => Done(Some(el), Empty)
case Empty => Cont(step)
case EOF => Done(None, EOF)
}
Cont(step)
}
def peek[E]: IterV[E, Option[E]] = {
def step: StreamG[E] => IterV[E, Option[E]] = {
case c@El(el) => Done(Some(el), c)
case Empty => Cont(step)
case EOF => Done(None, EOF)
}
Cont(step)
}
def drop[E]: Int => IterV[E, Unit] = {
case 0 => Done((), Empty)
case n => {
def step: StreamG[E] => IterV[E, Unit] = {
case El(_) => drop(n - 1)
case Empty => Cont(step)
case EOF => Done((), EOF)
}
Cont(step)
}
}
def length[E]: IterV[E, Int] = {
def step: (Int, StreamG[E]) => IterV[E, Int] = {
case (acc, El(_)) => Cont(step.curried(acc + 1))
case (acc, Empty) => Cont(step.curried(acc))
case (acc, EOF) => Done(acc, EOF)
}
Cont(step.curried(0))
}
view raw c.scala hosted with ❤ by GitHub


Iterateeたち。
これらをストリームに適用し、結果を得ます。curriedとか初めて使った気がします。
型が消えてしまうので、match式のところはwarningがいっぱいです。
この対処法がないのが残念なところ。(あったら教えてください

implicit def IterVMonad[E] = new Monad[({type X[A] = IterV[E, A]})#X] {
def pure[A](x: => A): IterV[E, A] = Done(x, Empty)
def bind[A, B](m: IterV[E, A], f: A => IterV[E, B]): IterV[E, B] = m match {
case Done(x, str) => f(x) match {
case Done(x, _) => Done(x, str)
case Cont(k) => k(str)
}
case Cont(k) => Cont((str: StreamG[E]) => bind(k(str), f))
}
}
view raw d.scala hosted with ❤ by GitHub


モナド。
PartialApplyを使おうとして嵌りました。定義のところで使っちゃダメなんですね・・・・
このインスタンスを作ることで、合成(>>=や>|>)を使うことができます。
Haskellと違って、Monadを定義すればFunctorやApplicativeがついてくるのでちょっと楽。

実行例

def f[E](l: List[E]) = run(enum(drop(2) >|> length, l))
f(List(1, 2, 3)) assert_=== Some(1)
f(List(1, 2, 3, 4, 5)) assert_=== Some(3)
f(List(1)) assert_=== Some(0)
view raw e.scala hosted with ❤ by GitHub


Haskellのコードそのままに書けるのは感動ですね。
次はIOを実装しようと思います。