Hatena::ブログ(Diary)

kaishitaeiichiの日記

2012-08-06 Scala Streamで無限に要素をもつコレクションをあつかう

Scala Streamで無限に要素をもつコレクションをあつかう

Stream - Scala Standard Library API (Scaladoc) 2.10.1 - scala.collection.immutable.Streamをつかうと、無限に要素をもつコレクションをあつかえるらしい。

実際のところは、要素の生成を後回しにして、無限の要素があるかのようにふるまうということらしい。

Javaだと、なつかしいところで、LazyList (Commons Collections 4.0-SNAPSHOT API)こんなのもつかったことあったなあ。

Streamもやっぱり、要素を生成する処理を記述して、使用する。

scala> def makeSameElement(x: Int): Stream[Int] = Stream.cons(x, makeSameElement(x))
makeSameElement: (x: Int)Stream[Int]

scala> makeSameElement(1) take 10
res6: scala.collection.immutable.Stream[Int] = Stream(1, ?)

scala> val a = makeSameElement(1) take 10
a: scala.collection.immutable.Stream[Int] = Stream(1, ?)

scala> a foreach println
1
1
1
1
1
1
1
1
1
1

Stream.consは、#::でもよいらしい。


scala> def makeNaturalNumber(x: Int): Stream[Int] = x #:: makeNaturalNumber(x + 1)
makeNaturalNumber: (x: Int)Stream[Int]

scala> val b = makeNaturalNumber(1) take 10
b: scala.collection.immutable.Stream[Int] = Stream(1, ?)

scala> b.foreach(println)
1
2
3
4
5
6
7
8
9
10

scala>

2012-08-05 Scala scala.util.Randomで乱数を生成する。

scala.util.Randomで乱数を生成する。

1から10までのランダムな数をつくるのはどうやるんだろう。

Random - Scala Standard Library API (Scaladoc) 2.10.1 - scala.util.Randomを見てみたが、おおむねjava.util.Randomとおなじか?

scala> import scala.util.Random
import scala.util.Random

scala> val r = new Random
r: scala.util.Random = scala.util.Random@5f04eb

scala> r.nextInt
res173: Int = -49067135

scala> r.nextInt(10)
res175: Int = 4

scala> r.nextInt(10) + 1
res176: Int = 1

ランダムな数字のリストがほしい

scala> r.shuffle((1 to 10).toSeq)
res37: scala.collection.immutable.IndexedSeq[Int] = Vector(7, 4, 8, 9, 1, 3, 10, 5, 2, 6)

ちょっとちがうかな。

こうかなあ

scala> def r10 = r.nextInt(10) + 1
r10: Int

scala> r10
res168: Int = 10

scala> r10
res169: Int = 1

scala> def infinitR10: Stream[Int] = Stream.cons(r10, infinitR10)
infinitR10: Stream[Int]

scala> infinitR10 take 20
res171: scala.collection.immutable.Stream[Int] = Stream(6, ?)

scala> infinitR10 take 20 foreach println
10
2
1
8
6
6
4
8
5
4
9
7
10
2
6
7
6
2
4
10

scala>

あれ?なんか数が偏っている?一様になってないかな。うーん。集計してみる。

scala> b.foldLeft (Map[Int, Int]()) { (acc: Map[Int, Int], e: Int) =>
     |     acc + (e -> (acc.getOrElse(e, 0) + 1))
     | }
res208: scala.collection.immutable.Map[Int,Int] = Map(5 -> 6, 1 -> 1, 6 -> 2, 9 -> 3, 2 -> 2, 7 -> 1, 3 -> 1, 8 -> 2, 4 -> 2)

scala> val c = infinitR10 take 10000
c: scala.collection.immutable.Stream[Int] = Stream(4, ?)

scala> c.foldLeft (Map[Int, Int]()) { (acc: Map[Int, Int], e: Int) =>
     |     acc + (e -> (acc.getOrElse(e, 0) + 1))
     | }
res209: scala.collection.immutable.Map[Int,Int] = Map(5 -> 1038, 10 -> 1028, 1 -> 964, 6 -> 1008, 9 -> 1011, 2 -> 1018, 7 -> 1009, 3 -> 1000, 8 -> 930, 4 -> 994)


もっと多くのデータで!

ヒープのサイズを増やして、ScalaREPLを起動しなおす。


F:\Data\ProgrammingLanguage\Scala\play-projects>scala -DXmx1024m
Welcome to Scala version 2.9.0.1 (Java HotSpot(TM) Client VM, Java 1.7.0_02).
Type in expressions to have them evaluated.
Type :help for more information.

scala> import scala.util.Random
import scala.util.Random

scala> val r = new Random
r: scala.util.Random = scala.util.Random@d7ba5b

scala> def r10 = r.nextInt(10) + 1
r10: Int

scala> def infinitR10: Stream[Int] = Stream.cons(r10, infinitR10)
infinitR10: Stream[Int]

scala> val d = infinitR10 take 1000000
d: scala.collection.immutable.Stream[Int] = Stream(1, ?)

scala> val result = d.foldLeft (Map[Int, Int]()) { (acc: Map[Int, Int], e: Int) =>
     | acc + (e -> (acc.getOrElse(e, 0) + 1))
     | }
result: scala.collection.immutable.Map[Int,Int] = Map(5 -> 100161, 10 -> 99790, 1 -> 99934, 6 -> 99675, 9 -> 99919, 2 -> 99738, 7 -> 99758, 3 -> 100131, 8 -> 100429, 4 -> 100465)

scala> import scala.collection.immutable.TreeMap
import scala.collection.immutable.TreeMap

scala> val result2 = TreeMap[Int, Int]()
result2: scala.collection.immutable.TreeMap[Int,Int] = Map()

scala> result2 ++ result
res6: scala.collection.immutable.TreeMap[Int,Int] = Map(1 -> 99934, 2 -> 99738, 3 -> 100131, 4 -> 100465, 5 -> 100161, 6 -> 99675, 7 -> 99758, 8 -> 100429, 9 -> 99919, 10 -> 99790)

scala>

さらに要素の数を1000000から10000000にしたら、Out Of Memoryになってしまった。そうならないためのStreamではないのか?自分がなにかまちがっているのか。うーん。。。。

Stream - Scala Standard Library API (Scaladoc) 2.10.1 - scala.collection.immutable.Streamにある例のIteratorを使う方法を試してみる。

scala> import scala.util.Random
import scala.util.Random

scala> val r = new Random
r: scala.util.Random = scala.util.Random@d7ba5b

scala> def r10 = r.nextInt(10) + 1
r10: Int

scala> val it = new Iterator[Int] {
     | def hasNext = true
     | def next: Int = { r10 }
     | }
it: java.lang.Object with Iterator[Int] = non-empty iterator

scala> val d = it take 100000000
d: Iterator[Int] = non-empty iterator

scala> val result = d.foldLeft (Map[Int, Int]()) { (acc: Map[Int, Int], e: Int) =>
     | acc + (e -> (acc.getOrElse(e, 0) + 1))
     | }
result: scala.collection.immutable.Map[Int,Int] = Map(5 -> 9999613, 10 -> 9998925, 1 -> 10005035, 6 -> 10004810, 9 -> 9992785, 2 -> 9995009, 7 -> 9999772, 3 -> 10002721, 8 -> 10000349, 4 -> 10000981)

scala> import scala.collection.immutable.TreeMap
import scala.collection.immutable.TreeMap

scala> val result2 = TreeMap[Int, Int]()
result2: scala.collection.immutable.TreeMap[Int,Int] = Map()

scala> result2 ++ result
res7: scala.collection.immutable.TreeMap[Int,Int] = Map(1 -> 10005035, 2 -> 9995009, 3 -> 10002721, 4 -> 10000981, 5 -> 9999613, 6 -> 10004810, 7 -> 9999772, 8 -> 10000349, 9 -> 9992785, 10 -> 9998925)

scala>

おおー、Iteratorだと、10000000どころか100000000でもだいじょうぶだ。

もはや、主題がRandomのはなしでなくなってしまったが、、、、Streamはつかいかたは、勉強だな。とりあえずは、Iteratorがお手軽だと。

2012-05-25

ScalaのcomposeとandThen

f(g(x))なのかg(f(x))なのかすぐにわすれちゃう。メモしておこう。

scala> val f = (x: Int) => 2 * x
f: (Int) => Int = <function1>

scala> val g = (x: Int) => x + 1
g: (Int) => Int = <function1>

scala> f(g(1))
res9: Int = 4

scala> (f compose g)(1)
res10: Int = 4

scala> g(f(1))
res11: Int = 3

scala> (f andThen g)(1)
res12: Int = 3

scala>

2012-05-07 Scala PartialFunction 部分関数

Scala PartialFunction 部分関数

PartialFunction


結局、部分関数とは、なんでしょう?

やっぱり、限られた範囲で定義した関数を、部分関数とよんでいるようだ。

自分の中で思い浮かんだ例としては、高校の数学でやった定義域のある関数を思い出した。

Scalaの部分関数というのは、定義域のある関数を表現するようなもののように見える。この定義域なら、こんな関数を適用する。この定義域でないなら、何もしない。それを表現するもの。

定義域X1で定義された関数はf, 定義域X2で定義された関数はg, 定義域X3で定義された関数はh,,,,のように、定義域ごとにバラバラに関数を定義するから、部分関数って表現なんだろうか。

そうすると、ScaladocPartialFunction - Scala Standard Library API (Scaladoc) 2.10.1 - scala.PartialFunction

  • abstract def apply(v1: A): B
    • Apply the body of this function to the argument.
  • abstract def isDefinedAt(x: A): Boolean
    • Checks if a value is contained in the function's domain.

というのも、そのまんま、しっくりくるかなあ。さらに、

  • def orElse[A1 <: A, B1 >: B](that: PartialFunction[A1, B1]): PartialFunction[A1, B1]

これも、f(X1)とg(X2)とh(X3)を、ひとつの関数にするものとして、ピンとくるな

あらためて、部分関数を調べてみると、プログラミングや情報科学ではなくて、数学の概念としてちゃんとあった

Function (mathematics) - Wikipedia, the free encyclopedia

これを見ると、部分関数というのは、定義域の一部に対して、定義されている関数のこというわけか。なるほどー。

関数型言語をやるときは、用語がどこに由来しているか、ちょっと調べるといいのかもな。そのプログラミング言語特有なのか、情報科学なのか、数学なのか。