Wednesday, December 22, 2010

Rails3で動的にログレベルを変更する

Rails3で大量データをBulkInsertで、大量データをActiveRecord経由でInsertしまくったんだけどさ、log/devlelopment.logみたらなんだかこんなwarningが大量に吐かれてるんですよ。

WARNING: Can't mass-assign protected attributes: column_id

importした行数分。

こりゃいかんということでちょっと調べたけど、わがらながったのでさ、
めんどくせぇからImportの時だけ一時的にログレベルを変更するという外道的解決をした時のメモ。

Rails.logger.levelを変えたらできました。

Rails.logger.level = 0 ... debug
Rails.logger.level = 3 ... error
ほかは調べてないけど、ログファイル見ながらlevelをかえれば分かるはず。

Rails3で大量データをBulkInsert

import元のOracleからActiveRecord経由で大量データをimportするときに
Model.create とかModel.new -> Model.saveだとSQLがマシンガンのようにながれまくるので、いつまで待っても終わらない。

そりゃ、SQL一発でバルクインサートでしょうってことで、このへんをみながらやってみた。
activerecord-import
Bulk insertion of data with ActiveRecord

log/development.logを見ながら確認したんだけど、
SQLiteだとバルクインサート的に書いても、SQLが連発される。
MySQLにしたらInsert文が1発のみだった。

Saturday, November 13, 2010

S25

S-99: Ninety-Nine Scala Problemsを試してみる。
勉強のためにListのAPIはなるべく使わない方向。

  1. // P25 (*) Generate a random permutation of the elements of a list.  
  2. // Hint: Use the solution of problem P23.  
  3. // Example:  
  4. // scala> randomPermute(List('a, 'b, 'c, 'd, 'e, 'f))  
  5. // res0: List[Symbol] = List('b, 'a, 'd, 'c, 'e, 'f)  
  6.   
  7. // P20 (*) Remove the Kth element from a list.  
  8. def removeAt[T](i: Int, xs: List[T]) = {  
  9.   def r(i: Int, xs: List[T], acc: List[T]): (List[T], T) = (i, xs) match {  
  10.     case (0, h :: t) => (acc.reverse ::: t, h)  
  11.     case (i, h :: t) => r(i - 1, t, h :: acc)  
  12.   }  
  13.   if(i < 0 || xs.size <= i) throw new NoSuchElementException else r(i, xs, Nil)  
  14. }  
  15.   
  16. import scala.util.Random  
  17. def randomPermute[T](xs: List[T]) = {  
  18.   val rand = new Random  
  19.   def r(ys: List[T], acc: List[T]): List[T] = {  
  20.     if(ys.size == 1) ys.head :: acc  
  21.     else {  
  22.       val (rest, removed) = removeAt(rand.nextInt(ys.size), ys)  
  23.       r(rest, removed :: acc)  
  24.     }  
  25.   }  
  26.   if(xs.isEmpty) Nil else r(xs, Nil)  
  27. }  
解答例
またもや、してやられたぜ!

S24

S-99: Ninety-Nine Scala Problemsを試してみる。
勉強のためにListのAPIはなるべく使わない方向。

  1. // P24 (*) Lotto: Draw N different random numbers from the set 1..M.  
  2. // Example:  
  3. // scala> lotto(6, 49)  
  4. // res0: List[Int] = List(23, 1, 17, 33, 21, 37)  
  5.   
  6. import scala.util.Random  
  7. def lotto(n: Int, to: Int) = {  
  8.   val rand = new Random()  
  9.   def r(acc: List[Int]): List[Int] = {  
  10.     def next(): Int = {  
  11.       val i = rand.nextInt(to)  
  12.       if(acc.count(_ == i) == 0) i else next  
  13.     }  
  14.     if(acc.size < n) r(next :: acc) else acc  
  15.   }  
  16.   if(n < 1 || to < n) throw new IllegalArgumentException  
  17.   else r(Nil)  
  18. }  
解答例
こりゃ一本とられたわい

S23

S-99: Ninety-Nine Scala Problemsを試してみる。
勉強のためにListのAPIはなるべく使わない方向。

  1. // P23 (**) Extract a given number of randomly selected elements from a list.  
  2. // Example:  
  3. // scala> randomSelect(3, List('a, 'b, 'c, 'd, 'f, 'g, 'h))  
  4. // res0: List[Symbol] = List('e, 'd, 'a)  
  5.   
  6. import scala.util.Random  
  7.   
  8. // P20 (*) Remove the Kth element from a list.  
  9. def removeAtR[T](i: Int, xs: List[T]) = {  
  10.   def r(i: Int, xs: List[T], acc: List[T]): (List[T], T) = (i, xs) match {  
  11.     case (0, h :: t) => (acc.reverse ::: t, h)  
  12.     case (i, h :: t) => r(i - 1, t, h :: acc)  
  13.   }  
  14.   if(i < 0 || xs.size <= i) throw new NoSuchElementException else r(i, xs, Nil)  
  15. }  
  16.   
  17. def randomSelect[T](n: Int, xs: List[T]) = {  
  18.   val rand = new Random()  
  19.   def r(ys: List[T], acc: List[T]): List[T] = {  
  20.     val (rest, removed) = removeAtR(rand.nextInt(ys.size), ys)  
  21.     if(n <= acc.size + 1) removed :: acc  
  22.     else r(rest, removed :: acc)  
  23.   }  
  24.   if(n <= 0 || xs.size < n) throw new IllegalArgumentException  
  25.   else r(xs, Nil)  
  26. }  
解答例
君のは違うけど、わしのは末尾再帰だよ。

Friday, November 12, 2010

Scalaでいい感じにtap

最近のRubyにある、超便利メソッドtapの使い方のメモ。
Scalaでimplicit conversionを使ったtapの実装はScala で tap メソッドを使う - Rainy Day Codingsに書いてある。

メソッドチェーンを切らずにtapしてprintlnとかよくやるけど、今日はそれ以外の使い方を学んだ。うはは。

tapを使わない場合は気の毒で目も当てられない

  1. import java.util.Properties  
  2. def loadProperties(path: String): Properties = {  
  3.   val p = new Properties()  
  4.   p.load(new FileInputStream(new File(path).getAbsolutePath))  
  5.   p  
  6. }  
オブジェクト作って呼び出し元に返したいが、
初期化メソッドの戻り値がthisじゃないからローカル変数に一度入れてからreturnしなきゃならんっていう古いjavaライブラリによくあるケース。

tapを使うとローカル変数がいらなくなる

  1. import java.util.Properties  
  2. def loadProperties(path: String): Properties = {  
  3.   new Properties().tap( _.load(new FileInputStream(new File(path).getAbsolutePath)))  
  4. }  

いいねぇ!

S22

S-99: Ninety-Nine Scala Problemsを試してみる。
勉強のためにListのAPIはなるべく使わない方向。

  1. // P22 (*) Create a list containing all integers within a given range.  
  2. //  Example:  
  3. // scala> range(4, 9)  
  4. // res0: List[Int] = List(4, 5, 6, 7, 8, 9)  
  5.   
  6. def rangeTail(from: Int, to: Int) = {  
  7.   def r(current: Int, acc: List[Int]): List[Int] = {  
  8.     if(current <= to) r(current + 1, current :: acc)  
  9.     else acc.reverse  
  10.   }  
  11.   r(from, Nil)  
  12. }  
  13.   
  14. def rangeBuiltin(from: Int, to: Int) = List.range(from, to + 1).toList  
解答例
unfoldRightっていう発想はなかった。 だけど、末尾再帰じゃないじゃないか。 これじゃすぐstackoverflowだ。 ということで、unfoldRightの末尾再帰版を書いてみた。
  1. def unfoldRightTail[A, B](s: B)(f: B => Option[(A, B)]): List[A] = {  
  2.   def recursive(s: B, acc: List[A]): List[A] = {  
  3.     f(s) match {  
  4.       case None         => acc.reverse  
  5.       case Some((r, n)) => recursive(n, r :: acc)  
  6.     }  
  7.   }  
  8.   recursive(s, Nil)  
  9. }  
  10. def rangeFunctionalTail(start: Int, end: Int): List[Int] =  
  11.   unfoldRightTail(start) { n =>  
  12.     if (n > end) None  
  13.     else Some((n, n + 1))  
  14.   }  

Thursday, November 11, 2010

scalaでstructural typingでreflection

Scala: How do I dynamically instantiate an object and invoke a method using reflection?

にstructural typingを使ったサンプルが載ってたのでメモ

  1. class Foo {  
  2.   def hello(name: String): String = "Hello there, %s".format(name)  
  3. }  
  4.   
  5. object FooMain {  
  6.   
  7.   def main(args: Array[String]) {  
  8.     val foo  = Class.forName("Foo").newInstance.asInstanceOf[{ def hello(name: String): String }]  
  9.     println(foo.hello("Walter")) // prints "Hello there, Walter"  
  10.   }  
  11. }  

Wednesday, November 10, 2010

S21

S-99: Ninety-Nine Scala Problemsを試してみる。
勉強のためにListのAPIはなるべく使わない方向。

  1. // P21 (*) Insert an element at a given position into a list.  
  2. // Example:  
  3. // scala> insertAt('new, 1, List('a, 'b, 'c, 'd))  
  4. // res0: List[Symbol] = List('a, 'new, 'b, 'c, 'd)  
  5.   
  6. def insertAt[T](e :T, n: Int, xs: List[T]) = {  
  7.   def r(n: Int, rest: List[T], acc: List[T]): List[T] = (n, rest) match {  
  8.     case (0, h :: t) => acc.reverse ::: List(e) ::: rest  
  9.     case (_, h :: t) => r(n - 1, t, h :: acc)  
  10.   }  
  11.   if(n < 0 || xs.size <= n) throw new NoSuchElementException else r(n, xs, Nil)  
  12. }  
  13.   
  14. def insertAt2[T](e :T, n: Int, xs: List[T]) = {  
  15.   if(n < 0 || xs.size <= n) throw new NoSuchElementException  
  16.   val splitted = xs.splitAt(n)  
  17.   splitted._1 ::: List(e) :::  splitted._2  
  18. }  
解答例
君、それ好きだよね。

Tuesday, November 9, 2010

S20

S-99: Ninety-Nine Scala Problemsを試してみる。
勉強のためにListのAPIはなるべく使わない方向。

  1. // P20 (*) Remove the Kth element from a list.  
  2. // Return the list and the removed element in a Tuple. Elements are numbered from 0.  
  3. // Example:  
  4. // scala> removeAt(1, List('a, 'b, 'c, 'd))  
  5. // res0: (List[Symbol], Symbol) = (List('a, 'c, 'd),'b)  
  6.   
  7. def removeAt[T](i: Int, xs: List[T]) =  
  8.   if(i < 0 || xs.size <= i) throw new NoSuchElementException  
  9.   else (xs.zipWithIndex.filter{_._2 != i}.map{_._1}, xs(i))  
  10.   
  11. def removeAtR[T](i: Int, xs: List[T]) = {  
  12.   def r(i: Int, xs: List[T], acc: List[T]): (List[T], T) = (i, xs) match {  
  13.     case (0, h :: t) => (acc.reverse ::: t, h)  
  14.     case (i, h :: t) => r(i - 1, t, h :: acc)  
  15.   }  
  16.   if(i < 0 || xs.size <= i) throw new NoSuchElementException else r(i, xs, Nil)  
  17. }  
解答例の上のやつ、いいね。

Monday, November 8, 2010

scalaでactor使ってparallel map その3 - Futures編

その1
その2
でparallel mapの実装を試みたところActorの理解が浅く、実はシングルスレッドだったという衝撃の事実が発覚して度肝を抜かれた。

めげずに、Using scala actor framework as fork-join computation?とかScalaActors.pdf
を参考にしてFuturesを使って実装してみた。

今回は、 FuturesをListの要素数分作って、mapでFuturesをapplyする場合と、
Futuresの数を制御したい場合の2パターンを実装してみた。

  1. import scala.actors.Future  
  2. import scala.actors.Futures._  
  3.   
  4. import java.util.concurrent._  
  5.   
  6. trait Pmap {  
  7.   
  8.   // FuturesをListの要素数分作る場合  
  9.   def pmap[T, U](xs: List[T])(fun: T => U): List[U] = {  
  10.     val mapfuncs = xs.map{ x => future { fun(x) } }  
  11.     mapfuncs.map{ _() }  
  12.   }  
  13.   
  14.   // for Debug  
  15.   def pmap_debug[T, U](xs: List[T])(fun: T => U): List[U] = {  
  16.     val mapfuncs = xs.map{ x => future {  
  17.         println("start Thread " + currentThread.getId)  
  18.         val r = fun(x)  
  19.         println("end Thread " + currentThread.getId)  
  20.         r  
  21.     } }  
  22.     mapfuncs.map{ _() }  
  23.   }  
  24.   
  25.   // Futuresの数を制限したい場合  
  26.   def pmap[T, U](xs: List[T], n: Int)(fun: T => U): List[U] = {  
  27.     val mapfuncs = divide(n, xs).map{ l =>  
  28.       future { l.map( fun(_) ) }  
  29.     }  
  30.     mapfuncs.flatMap{ _() }  
  31.   }  
  32.   
  33.   // for Debug  
  34.   def pmap_debug[T, U](xs: List[T], n: Int)(fun: T => U): List[U] = {  
  35.     val mapfuncs = divide(n, xs).map{ l =>  
  36.       future {  
  37.         println("start Thread " + currentThread.getId)  
  38.         val result = l.map( fun(_) )  
  39.         println("end Thread " + currentThread.getId)  
  40.         result  
  41.       }  
  42.     }  
  43.     mapfuncs.flatMap{ _() }  
  44.   }  
  45.   
  46.   def divide[T](n: Int, xs: List[T]): List[List[T]] = {  
  47.     val size = xs.size / n  
  48.     def r(ys: List[T], acc: List[List[T]]): List[List[T]] = {  
  49.       if(ys.size < size) (acc.head ::: ys) :: acc.tail  
  50.       else{  
  51.         val splitted = ys.splitAt(size)  
  52.         r(splitted._2, splitted._1 :: acc)  
  53.       }  
  54.     }  
  55.     r(xs, Nil).reverse  
  56.   }  
  57. }  
  58.   
  59. object Main extends Application with Pmap {  
  60.   
  61.   val l: List[Int] = (1 to 100000).toList  
  62.   pmap[Int, Int](l, 4)(x => x + 1)  
  63.   pmap_debug[Int, Int](l, 2)(x => x + 1)  
  64.   pmap[Int, Int](l)(x => x + 1)  
  65.   pmap_debug[Int, Int](l)(x => x + 1)  
  66. }  

pmap_debugを実行すると
start Thread 13
start Thread 11
start Thread 12
start Thread 10
end Thread 10
end Thread 11
end Thread 12
end Thread 13

と出るのでマルチスレッドで非同期に実行されていることが確認できた。

Futures10万個の場合では実際に(2コア2スレッドのマシンでは)4スレッドで切り盛りしていた。
(環境依存。4コア8スレッドのマシン上では合計16スレッドだった)

2コア2スレッドマシン
% sort /tmp/output.txt |uniq -d
end Thread 10
end Thread 11
end Thread 12
end Thread 13
start Thread 10
start Thread 11
start Thread 12
start Thread 13

どっちがよいかは場合によるだろう。

リストの数がそれほど大きくなくて、mapにそこそこ時間がかかる場合を考えてみる。
リストをまず分割して、その断片にFuturesを割り当てる方式だと、
分割したリスト断片間を処理する時間にばらつきがあると、一番遅い断片の処理時間に引っ張られそう。
リストの要素ごとにFuturesを作った方が処理時間が平準化されてトータルでは早くなりそうだ。

今回のようにリストの数が膨大だとFuturesの数を抑えたが方が、高速でメモリにもやさしそうだ。

リストの要素数、mapの処理内容、CPUコア数によって変わるだろうから実際に動かして決めるのが良さそうだな。

scalaでactor使ってparallel map その2

-----------
これもシングルスレッドだ。パラレルじゃない。Futureを使わないFork-Joinは再チャレンジする(11/8追記)
----------

前回の実装はイケてない。
pmapの関数定義の結果型がList[Any](実際はList[List[T]])だった。
map的にはList[T]を返した方が自然だよな。

ということで改良してみた。

  1. import scala.actors.Actor._  
  2.   
  3. @SuppressWarnings(Array("unchecked"))  
  4. def pmap[T, U](xs: List[T], n: Int)(fun: T => U): List[U] = {  
  5.   
  6.   def divide(n: Int, xs: List[T]): List[List[T]] = {  
  7.     val size = xs.size / n  
  8.     def r(ys: List[T], acc: List[List[T]]): List[List[T]] = {  
  9.       if(ys.size < size) (acc.head ::: ys) :: acc.tail  
  10.       else{  
  11.         val splitted = ys.splitAt(size)  
  12.         r(splitted._2, splitted._1 :: acc)  
  13.       }  
  14.     }  
  15.     r(xs, Nil).reverse  
  16.   }  
  17.   
  18.   val mapped: List[List[U]]  = divide(n, xs).map{ l =>  
  19.     val a = actor { receive { case _ => reply(l.map(fun(_))) } }  
  20.     a !? "s" match {  
  21.       case l: List[U] => l  
  22.       case _ => Nil  
  23.     }  
  24.   }  
  25.   
  26.   mapped.flatten  
  27. }  
  28.   
  29. val l = (1 to 100).toList  
  30. val result = pmap[Int, Int](l, 4)(_ + 1)  
  31.   
  32. println(result)  

実行すると、
warning: non variable type-argument U in type pattern List[U] is unchecked since it is eliminated by erasure
case l: List[U] => l
^
one warning found
List(2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101)
となる。

erasureによって型Uが消されてるからcase List[U]がU以外でもマッチしてあぶねーよ、っていわれてる。
@SuppressWarnings(Array("unchecked"))書いても警告がでるのね。
無視スリゃいいんだろうけど気持ち悪い。

scalaでactor使ってparallel map その3 - Futures編に続く。

Saturday, November 6, 2010

scalaでactor使ってparallel map その1

-----------
これ、シングルスレッドだ。パラレルじゃない。Futureを使わないFork-Joinは再チャレンジする(11/8追記)
----------

試しに書いてみた。

pmapの結果型がList[T]だと型チェックエラーでコンパイルできない。
replyすると型情報が消えちまうのか?

パラレルマップの正解はこれとかこれかもしれない。
また今度試す。

  1. import scala.actors.Actor._  
  2.   
  3. def pmap[T](xs: List[T], n: Int)(fun: T => T): List[Any] = {  
  4.   
  5.   def divide(n: Int, xs: List[T]): List[List[T]] = {  
  6.     val size = xs.size / n  
  7.     def r(ys: List[T], acc: List[List[T]]): List[List[T]] = {  
  8.       if(ys.size < size) (acc.head ::: ys) :: acc.tail  
  9.       else{  
  10.         val splitted = ys.splitAt(size)  
  11.         r(splitted._2, splitted._1 :: acc)  
  12.       }  
  13.     }  
  14.     r(xs, Nil).reverse  
  15.   }  
  16.   
  17.   divide(n, xs).map{ l =>  
  18.     val a = actor { receive { case _ => reply(l.map(fun(_))) } }  
  19.     a !? "s"  
  20.   }  
  21. }  
  22.   
  23. val l = (1 to 100).toList  
  24. val result = pmap(l, 4)(_ + 1)  
  25.   
  26. println(result)  

実行結果
List(List(2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26), List(27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51), List(52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101))

scalaでactor使ってparallel map その2に続く。

S19

S-99: Ninety-Nine Scala Problemsを試してみる。
勉強のためにListのAPIはなるべく使わない方向。

  1. // P19 (**) Rotate a list N places to the left.  
  2. // Examples:  
  3. // scala> rotate(3, List('a, 'b, 'c, 'd, 'e, 'f, 'g, 'h, 'i, 'j, 'k))  
  4. // res0: List[Symbol] = List('d, 'e, 'f, 'g, 'h, 'i, 'j, 'k, 'a, 'b, 'c)  
  5. // scala> rotate(-2, List('a, 'b, 'c, 'd, 'e, 'f, 'g, 'h, 'i, 'j, 'k))  
  6. // res1: List[Symbol] = List('j, 'k, 'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h, 'i)  
  7.   
  8. def rotate[T](i: Int, xs: List[T]) = {  
  9.   val splitted = xs.splitAt(i)  
  10.   splitted._2 ::: splitted._1  
  11. }  
  12.   
  13. // match - case version  
  14. def rotateR[T](i: Int, xs: List[T]) = {  
  15.   def r(i: Int, xs: List[T], acc: List[T]): List[T] = (i, xs) match {  
  16.     case (_, h :: t) if 0 < i => r(i - 1, t, h :: acc) //tail recursion  
  17.     case (0, rest) => rest ::: acc.reverse // Only 1 time.  
  18.   }  
  19.   if(i < 0 || xs.size <= i) xs else r(i, xs, Nil)  
  20. }  
  21.   
  22. // if version  
  23. def rotateRIf[T](i: Int, xs: List[T]) = {  
  24.   def r(i: Int, xs: List[T], acc: List[T]): List[T] = {  
  25.     if (0 < i) r(i -1, xs.tail, xs.head :: acc ) //tail recursion  
  26.     else xs ::: acc.reverse // only 1 time.  
  27.   }  
  28.   if(i < 0 || xs.size <= i) xs else r(i, xs, Nil)  
  29. }  
  30.   
  31. val l = (1 to 1000000) toList  
  32.   
  33. println(rotate(999999, l)) // ok  
  34. println(rotateR(999999, l)) // ok  
  35. println(rotateRIf(999999, l)) // ok  
解答例
へそ曲がりめ!

Friday, November 5, 2010

S18

S-99: Ninety-Nine Scala Problemsを試してみる。
勉強のためにListのAPIはなるべく使わない方向。

  1. // P18 (**) Extract a slice from a list.  
  2. // Given two indices, I and K, the slice is the list containing the elements from and including the Ith element up to but not including the Kth element of the original list. Start counting the elements with 0.  
  3. // Example:  
  4. // scala> slice(3, 7, List('a, 'b, 'c, 'd, 'e, 'f, 'g, 'h, 'i, 'j, 'k))  
  5. // res0: List[Symbol] = List('d, 'e, 'f, 'g)  
  6.   
  7. def sliceBuiltin[T](i: Int, k: Int, xs: List[T]) = xs.slice(i, k)  
  8.   
  9. def slice[T](i: Int, k: Int, xs: List[T]) = xs.drop(i).take(k - i)  
  10.   
  11. def sliceZip[T](i: Int, k: Int, xs: List[T]) =  
  12.   xs.zipWithIndex.filter(x => i <= x._2).filter(x => x._2 < k).map(_._1)  
  13.   
  14. def sliceFoldL[T](i: Int, k: Int, xs: List[T]) =  
  15.   xs.foldLeft((0, List[T]()))((acc, x) =>  
  16.     if(i <= acc._1 && acc._1 < k) (acc._1 + 1, x :: acc._2)  
  17.     else (acc._1 + 1, acc._2)  
  18.   )._2.reverse  
  19.   
  20. def sliceRecursiveNotTail[T](i: Int, k: Int, xs: List[T]): List[T] = (i, k, xs) match {  
  21.   case (_, _, Nil)  => Nil  
  22.   case (0, _, h :: tail) if(0 < k) => h :: sliceRecursiveNotTail(0, k - 1, tail)  
  23.   case (_, _, _ :: tail) if(0 < i)  => sliceRecursiveNotTail(i - 1, k - 1, tail)  
  24.   case (_, 0, _) => Nil  
  25. }  
  26.   
  27. def sliceRecursiveTail[T](i: Int, k: Int, xs: List[T]) = {  
  28.   def recursive(i: Int, k: Int, xs: List[T], acc: List[T]): List[T] =  
  29.     (i, k, xs) match {  
  30.       case (_, _, Nil)  => acc  
  31.       case (0, _, h :: tail) if(0 < k) => recursive(0, k - 1, tail, h :: acc)  
  32.       case (_, _, _ :: tail) if(0 < i)  => recursive(i - 1, k - 1, tail, acc)  
  33.       case (0, 0, _) => acc  
  34.     }  
  35.   recursive(i, k, xs, Nil).reverse  
  36. }  
  37.   
  38. val l = (1 to 1000000) toList  
  39.   
  40. //println(slice(1, 110000, l))  
  41. //println(sliceZip(1, 110000, l))  
  42. //println(sliceFoldL(1, 110000, l))  
  43. println(sliceRecursiveNotTail(1, 110000, l)) // StackOverFlow  
  44. //println(sliceRecursiveTail(1, 110000, l))  

解答例
似たようなケースがある場合は、if文で書いた方がすっきりすることもあるのね。

Thursday, November 4, 2010

S17

S-99: Ninety-Nine Scala Problemsを試してみる。
勉強のためにListのAPIはなるべく使わない方向。

  1. // P17 (*) Split a list into two parts.  
  2. // The length of the first part is given. Use a Tuple for your result.  
  3. // Example:  
  4. // scala> split(3, List('a, 'b, 'c, 'd, 'e, 'f, 'g, 'h, 'i, 'j, 'k))  
  5. // res0: (List[Symbol], List[Symbol]) = (List('a, 'b, 'c),List('d, 'e, 'f, 'g, 'h, 'i, 'j, 'k))  
  6.   
  7. // tail revursion but too slow  
  8. def split_tail_too_slow[T](nth: Int, xs: List[T]) = {  
  9.   def recursive(n: Int, rest: List[T], acc: (List[T], List[T])): (List[T], List[T]) = rest match {  
  10.     case Nil => throw new NoSuchElementException  
  11.     case l if (n == 0) => (acc._1, l)  
  12.     case h :: t => recursive(n - 1, t, (acc._1 ::: List(h), Nil)) // add to tail -> O(n)  
  13.   }  
  14.   if(nth <= 0) throw new IllegalArgumentException else recursive(nth, xs, (Nil, Nil))  
  15. }  
  16.   
  17. // tail revursion  
  18. def split_tail_fast[T](nth: Int, xs: List[T]) = {  
  19.   def recursive(n: Int, rest: List[T], acc: (List[T], List[T])): (List[T], List[T]) = rest match {  
  20.     case Nil => throw new NoSuchElementException  
  21.     case l if (n == 0) => (acc._1.reverse, l)  
  22.     case h :: t => recursive(n - 1, t, (List(h) ::: acc._1 , Nil)) // add to head -> O(1)  
  23.   
  24.   }  
  25.   if(nth <= 0) throw new IllegalArgumentException else recursive(nth, xs, (Nil, Nil))  
  26. }  
  27.   
  28. def split_take[T](nth: Int, xs: List[T]): (List[T], List[T]) =  
  29.   (xs.take(nth) , xs.takeRight(xs.length - nth))  
  30.   
  31. val l = (1 to 1000000).toList  
  32. println(split_take(100000, l))  
  33. println(split_tail_fast(100000, l))  
  34. println(split_tail_too_slow(100000, l)) // 超遅い  
3方式で書いてみた。

split_tail_too_slowはリストの最後尾に追加する。追加の度にリストをたどらなければならないので、再帰の度に遅くなる。O(n)
split_tail_fastはリストの先頭に追加するため、リストの要素数に関係なくO(1)
split_tail_takeはList APIを使ったバージョン。


100万個のリストで(10万, 90万)で分割(split_take以外の2つは10万回再帰)してみたところ、
split_tail_too_slowはいつまでたっても終わらなかった。

末尾再帰にすりゃいいってもんじゃないのね。勉強になりました。

解答例
ふむふむ、splitAtってのがあるのね。
match式にタプルを使えばいいのか。if式がいらなくなるのね。なるほど。

S16

S-99: Ninety-Nine Scala Problemsを試してみる。
勉強のためにListのAPIはなるべく使わない方向。

  1. // P16 (**) Drop every Nth element from a list.  
  2. // Example:  
  3. // scala> drop(3, List('a, 'b, 'c, 'd, 'e, 'f, 'g, 'h, 'i, 'j, 'k))  
  4. // res0: List[Symbol] = List('a, 'b, 'd, 'e, 'g, 'h, 'j, 'k)  
  5.   
  6. // not tail recursive version  
  7. def drop_nottail[T](n: Int, xs: List[T]): List[T] = xs match {  
  8.   case h :: t if (n == 1) => drop_nottail(n - 1, t)  
  9.   case h :: t => h :: drop_nottail(n - 1, t)  
  10.   case Nil => xs  
  11. }  
  12.   
  13. // tail recursive version  
  14. def drop_tail[T](nth: Int, xs: List[T]) = {  
  15.   def recursive[T](n: Int, tail: List[T], acc: List[T]): List[T] = tail match {  
  16.     case h :: t if (n == 1) => recursive(n - 1, t, acc)  
  17.     case h :: t => recursive(n - 1, t, h :: acc)  
  18.     case Nil => acc  
  19.   }  
  20.   recursive(nth, xs, Nil).reverse  
  21. }  
  22.   
  23. // zipwithindex version  
  24. def drop_zipWithIndex[T](nth: Int, xs: List[T]) = {  
  25.   xs.zipWithIndex.flatMap{  
  26.     case (_, i) if (i + 1 == nth) => Nil // drop nth  
  27.     case (e, _) => e :: Nil  
  28.   }  
  29. }  
  30.   
  31. val l: List[Int] = (1 to 100000).toList  
  32. //println(drop_nottail(3, l)) // StackOverflowError  
  33. //println(drop_tail(3, l))  
  34. println(drop_zipWithIndex(3, l))  

解答例
そうまでして1行で書きたいってか!!

S15

S-99: Ninety-Nine Scala Problemsを試してみる。
勉強のためにListのAPIはなるべく使わない方向だけど、List要素の増殖は以前書いたので今回はList.fillを使った。

  1. // P15 (**) Duplicate the elements of a list a given number of times.  
  2. //     Example:  
  3. //     scala> duplicateN(3, List('a, 'b, 'c, 'c, 'd))  
  4. //     res0: List[Symbol] = List('a, 'a, 'a, 'b, 'b, 'b, 'c, 'c, 'c, 'c, 'c, 'c, 'd, 'd, 'd)  
  5.   
  6. def duplicateN[T](n: Int, xs: List[T]): List[T] = xs match {  
  7.   case Nil => xs  
  8.   case h :: t => List.fill(n)(h) ::: duplicateN(n, t)  
  9. }  
  10.   
  11. def duplicateN_tail[T](n: Int, xs: List[T]) = {  
  12.   def recursive[T](n: Int, tail: List[T], acc: List[T]): List[T] = tail match {  
  13.     case Nil => acc  
  14.     case h :: t => recursive(n, t, List.fill(n)(h) ::: acc)  
  15.   }  
  16.   recursive(n, xs, Nil).reverse  
  17. }  
  18.   
  19. def duplicateN_map[T](n: Int, xs: List[T]) = xs.flatMap(List.fill(n)(_))  
  20.   
  21. val l = List('a, 'b, 'c, 'c, 'd)  
  22. println(duplicateN_tail(100000, l))  
  23. println(duplicateN_map(100000, l))  
  24. println(duplicateN(100000, l))  // 末尾再帰じゃないはずだが、stackoverflowにならないのが不思議  

解答例
やっぱりそうきますか。

Wednesday, November 3, 2010

S14

S-99: Ninety-Nine Scala Problemsを試してみる。
勉強のためにListのAPIはなるべく使わない方向で。

  1. // P14 (*) Duplicate the elements of a list.  
  2. // Example:  
  3. // scala> duplicate(List('a, 'b, 'c, 'c, 'd))  
  4. // res0: List[Symbol] = List('a, 'a, 'b, 'b, 'c, 'c, 'c, 'c, 'd, 'd)  
  5.   
  6. def duplicate[T](xs: List[T]): List[T] = xs match {  
  7.   case h :: t => h :: h :: duplicate(t)  
  8.   case Nil => xs  
  9. }  
  10.   
  11. def duplicate_tail[T](xs: List[T]) = {  
  12.   def recursive(ys: List[T], acc: List[T]): List[T] = ys match {  
  13.     case Nil => acc  
  14.     case h :: t => recursive(t, h :: h :: acc)  
  15.   }  
  16.   recursive(xs, Nil).reverse  
  17. }  
  18.   
  19. def duplicate_map[T](xs: List[T]): List[T] = xs.flatMap{ x => x :: x :: Nil}  
  20.   
  21. //val l = List('a, 'b, 'c, 'c, 'd)  
  22. val l = 1 to 1000000 toList  
  23.   
  24. println(duplicate_tail(l))  
  25. println(duplicate_map(l))  
  26. println(duplicate(l)) // StackOverFlow  

解答例
そうですよね。

scala + ctags + vim + taglistできた

scalaの開発環境改善中。

まずは、ctagsをscalaに対応させる方法を見て、関数定義にタグジャンプできるようにした。

その後、taglist.vimを使ってみたのが、そのままではタグの一覧が表示されなかったのでググってみたらドンピシャな記事を発見。

Has anyone got the vim taglist plugin working with Scala?

↑に書いてあるとおり、taglist.vimの、
s:tlist_def_yacc_settings
の後ろに↓の2行追加したらできました。

let s:tlist_def_scala_settings = 'scala;t:trait;c:class;T:type;' .
\ 'm:method;C:constant;l:local;p:package;o:object'

ちなみに、タグジャンプ等のキーバインドは、
Vimの極め方 tags-and-searchesを使い易くする
この設定がシックリきてます。

Tuesday, November 2, 2010

S12

S-99: Ninety-Nine Scala Problemsを試してみる。
勉強のためにListのAPIはなるべく使わない方向で。

  1. //P12 (**) Decode a run-length encoded list.  
  2. //Given a run-length code list generated as specified in problem P10, construct its uncompressed version.  
  3. //Example:  
  4. //scala> decode(List((4, 'a), (1, 'b), (2, 'c), (2, 'a), (1, 'd), (4, 'e)))  
  5. //res0: List[Symbol] = List('a, 'a, 'a, 'a, 'b, 'c, 'c, 'a, 'a, 'd, 'e, 'e, 'e, 'e)  
  6.   
  7. def decode[T](xs: List[(Int, T)]) = {  
  8.   
  9.   // not tail recursion  
  10.   def ntimes_nottail(n: Int, x: T): List[T] = {  
  11.     if (n < 0) throw new IllegalArgumentException  
  12.     else if (n == 0) Nil  
  13.     else x :: ntimes_nottail(n - 1, x)  
  14.   }  
  15.   
  16.   // tail recursion  
  17.   def ntimes_tail(ntimes: Int, x: T) = {  
  18.     def ntimes_rec(n: Int, result: List[T]): List[T] = {  
  19.       if (n == 0) result else ntimes_rec(n - 1, x :: result)  
  20.     }  
  21.     if (ntimes < 0) throw new IllegalArgumentException else ntimes_rec(ntimes, Nil)  
  22.   }  
  23.   
  24.   // tail recursion  
  25.   def recursive(ys: List[(Int, T)], result: List[T]): List[T] = ys match {  
  26.     case Nil => result  
  27.     case (times, x) :: tail =>  recursive(tail, result ::: ntimes_tail(times, x))  
  28. //    case (times, x) :: tail =>  recursive(tail, result ::: ntimes_nottail(times, x))  
  29.   }  
  30.   
  31.   recursive(xs, Nil)  
  32. }  
  33.   
  34.   
  35. val l = List((5, 'a), (1, 'b), (2, 'c), (2, 'a), (1, 'd), (4, 'e))  
  36. println(decode(l))  

末尾再帰版(ntimes_tail)だと100万回のループでもStackOverFlowにならなかったが、
非末尾再帰版だと10万回でStackOverFlowした。

解答例
そ、そんな!!

vimからsbtを実行できた

ここに、scalaのakkaプロジェクト創始者のjboner君のvimrcがあったので、これは!!と思って覗いてみたら、vimからsimple-build-toolを使う部分があったので、試してみた。

ちょっとハマったのでメモしておく。

"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" For SBT
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
set makeprg=sbt-no-color\ test-compile
...省略...
set errorformat=%E[error]\ %f:%l:\ %m,%C[error]\ %p^,%-C%.%#,%Z,
\%W[warn]\ %f:%l:\ %m,%C[warn]\ %p^,%-C%.%#,%Z,
\%-G%.%#
となっている。

sbt-no-colorってなんぞや思いつつも、.vimrcにコピって:makeしてみたけど、sbt-no-colorがないと怒られる。

そこで、sbt-no-colorをsbtに変更して:makeすると、sbtでコンパイルしてるようなんだけど、
[0m[...のように文字化けてる風味で出力される。

:!sbt test-compile 2>&1| tee /tmp/vQCb1aG/2
[0m[ [0minfo [0m] [0mBuilding project test 1.0 against Scala 2.8.0 [0m
...省略...
[0m[ [32msuccess [0m] [0mBuild completed successfully. [0m

15分位ググっても引っかからん。うーんうーん唸っていたら僕ちゃん、気づきました。

「色」だ。 no-colorだ。

ということで。sbtのソース落としてgrep "color" **/*.scalaとかやったら出てきた。
in Logger.scala
private val formatEnabled = ansiSupported && !formatExplicitlyDisabled
private[this] def formatExplicitlyDisabled = java.lang.Boolean.getBoolean("sbt.log.noformat")

sbtを起動するシェルスクリプトを↓のように書き換え、
java -Dsbt.log.noformat=true -Xmx512M -jar /path_to_/sbt-launch-0.7.4.jar "$@"

sbt-no-colorという名前で保存後、jboner君のvimrcで、:makeでvim上からsbt使ってコンパイルすることができました。

---------
ちなみに、gvim上でエラー行にマークするには、
errormarker.vimがいいよ。

vimでscalaをomni補完するプラグイン codefellowが動かん

vimでscalaのomni補完ができるという
codefellow
を試したけど、1時間イジって動かなかったので諦めた。。
scalaのファイルを開くと固まる。

screeencast見たらすごすぎておったまげた。
ぜひ使わせてもらいたかったんだがなー。


もう少し時が満ちてから試す。
備忘録としてメモっとく。

Monday, November 1, 2010

scalaでDir.glob("**/*.sql")

RubyだとDir.glob("**/*.sql")で指定したディレクトリから、
再帰的に*.sqlのファイルパスを検索してくれるが、
scalaには見当たらなかったので、書いてみた。

  1. // glob **/*.sql   
  2. val globSqlFiles = glob((f: File) =>   
  3.   !f.isDirectory && f.getName.endsWith(".sql")) _  
  4.   
  5. // curried function  
  6. def glob(filter: (File) => Boolean)(dirs: List[String]): List[File] = {  
  7.   def recursive(dir: File, acc: List[File]): List[File] =   
  8.     Option(dir.listFiles) match {  
  9.       case None => throw new FileNotFoundException(dir.getAbsolutePath)  
  10.       case Some(lists) =>   
  11.         val filtered = lists.filter{ c =>  filter(c) }.toList  
  12.         val childDirs = lists.filter{ c => c.isDirectory && !c.getName.startsWith(".") }  
  13.         return ( (acc ::: filtered) /: childDirs){ (a, dir) => recursive(dir, a)}  
  14.   }  
  15.   dirs.flatMap{ d => recursive(new File(d), Nil)}  
  16. }  
  17.   
  18. // 使い方。対象ディレクトリはListで複数指定できる。  
  19. globSqlFiles(List("/tmp/sql"))  

汎用的になるようにカリー化してみた。
3、4行目の条件に正規表現を組み込めば曖昧検索できる。

S-99: Ninety-Nine Scala Problemsを頑張ってやっているせいか、
immutableなListの再帰に対してアレルギーがなくなってきた。

S10, S11

S-99: Ninety-Nine Scala Problemsを試してみる。
勉強のためにListのAPIはなるべく使わない方向で。

  1. // P10 (*) Run-length encoding of a list.  
  2. // Use the result of problem P09 to implement the so-called run-length encoding data compression method. Consecutive duplicates of elements are encoded as tuples (N, E) where N is the number of duplicates of the element E.  
  3. // Example:  
  4. // scala> encode(List('a, 'a, 'a, 'a, 'b, 'c, 'c, 'a, 'a, 'd, 'e, 'e, 'e, 'e))  
  5. // res0: List[(Int, Symbol)] = List((4,'a), (1,'b), (2,'c), (2,'a), (1,'d), (4,'e))  
  6.   
  7. def pack[A](ls: List[A]): List[List[A]] = {  
  8.   if (ls.isEmpty) List(List())  
  9.   else {  
  10.     val (packed, next) = ls span { _ == ls.head }  
  11.     if (next == Nil) List(packed)  
  12.     else{  
  13.       packed :: pack(next)  
  14.     }  
  15.   }  
  16. }  
  17. def encode[T](xs: List[T]) = {  
  18.   pack(xs).map{ (x) => (x.length, x.head) }  
  19. }  
  20.   
  21. def encodeModified[T](xs: List[T]) = {  
  22.   pack(xs).map{ (x) => if(x.length == 1) x.head else (x.length, x.head) }  
  23. }  

解答例
同じだ。

S09

S-99: Ninety-Nine Scala Problemsを試してみる。
勉強のためにListのAPIはなるべく使わない方向で。

  1. // P09 (**) Pack consecutive duplicates of list elements into sublists.  
  2. // If a list contains repeated elements they should be placed in separate sublists.  
  3. // Example:  
  4. // scala> pack(List('a, 'a, 'a, 'a, 'b, 'c, 'c, 'a, 'a, 'd, 'e, 'e, 'e, 'e))  
  5. // res0: List[List[Symbol]] = List(List('a, 'a, 'a, 'a), List('b), List('c, 'c), List('a, 'a), List('d), List('e, 'e, 'e, 'e))  
  6.   
  7. // tail recursion  
  8. def reverse[T](xs: List[T]): List[T] = {  
  9.   def recursive[T](ys: List[T], result: List[T]): List[T] = ys match {  
  10.     case Nil => result  
  11.     case h :: t => recursive(t, h :: result)  
  12.   }  
  13.   recursive(xs, Nil)  
  14. }  
  15.   
  16. // tail recursion  
  17. def removeLast[T](xs: List[T]): List[T] = {  
  18.   def recursive[T](ys: List[T], result: List[T]): List[T] = ys match {  
  19.     case Nil => throw new NoSuchElementException  
  20.     case h :: Nil => result  
  21.     case h :: t => recursive(t, h :: result)  
  22.   }  
  23.   reverse(recursive(xs, Nil))  
  24. }  
  25.   
  26. // tail recursion  
  27. def pack[T](xs: List[T]): List[List[T]] = {  
  28.   def recursive(rest: List[T], acc: List[List[T]]): List[List[T]] = {  
  29.     rest match {  
  30.       case Nil => acc  
  31.       case h :: t if(acc != Nil && h == acc.last.head) =>   
  32.         val nextAcc = List(h :: acc.last) //List[Listt[T]]  
  33.         recursive(t, removeLast(acc) ++ nextAcc) // List[List[T]] ++ List[List[T]] => List[List[T]]  
  34.       case h :: t =>  
  35.         val nextAcc = acc ++ List(List(h))  
  36.         recursive(t, nextAcc)  
  37.     }  
  38.   }  
  39.   recursive(xs, Nil)  
  40. }  
  41.   
  42. val l = List('a, 'a, 'a, 'a, 'b, 'c, 'c, 'a, 'a, 'd, 'e, 'e, 'e, 'e)  
  43. println(pack(l)) //=>  List(List('a, 'a, 'a, 'a), List('b), List('c, 'c), List('a, 'a), List('d), List('e, 'e, 'e, 'e))  

解答例
spanっすか。

Sunday, October 31, 2010

S08

S-99: Ninety-Nine Scala Problemsを試してみる。

  1. // P08 (**) Eliminate consecutive duplicates of list elements.  
  2. // If a list contains repeated elements they should be replaced with a single copy of the element. The order of the elements should not be changed.  
  3. // Example:  
  4. // scala> compress(List('a, 'a, 'a, 'a, 'b, 'c, 'c, 'a, 'a, 'd, 'e, 'e, 'e, 'e))  
  5. // res0: List[Symbol] = List('a, 'b, 'c, 'a, 'd, 'e)  
  6.   
  7. def compress[T](xs: List[T]): List[T] = {  
  8.   // simple reverse (not tail recursion..)  
  9.   def reverse[T](ys: List[T]): List[T] = ys match {  
  10.     case Nil => ys  
  11.     case head :: tail => reverse(tail) ::: List(head)  
  12.   }  
  13.   def recursive[T](rest: List[T], result: List[T]): List[T] = rest match{  
  14.     case Nil => result  
  15.     case head :: tail if(result.isEmpty || head != result.head) =>  
  16.         recursive(tail, List(head) ::: result)  
  17.     case _ :: tail => recursive(tail, result)  
  18.   }  
  19.   reverse(recursive(xs, Nil))  
  20. }  

解答例

またおまえか、foldRight!!
そりゃ、試すさ。

  1. // FoldLeft  
  2. def compressFoldL[T](xs: List[T]): List[T] =   
  3.   xs.foldLeft(List[T]()){ (acc, x) =>    
  4.     if(acc.isEmpty || acc.last != x) acc ::: List(x)  
  5.     else acc  
  6.   }  
  7.   
  8. // /: (FoldLeft)  
  9. def compressFoldL2[T](xs: List[T]): List[T] =   
  10.   (List[T]() /: xs){ (acc, x) =>    
  11.     if(acc.isEmpty || acc.last != x) acc ::: List(x)  
  12.     else acc  
  13.   }  
  14.   
  15. // FoldRight  
  16. def compressFildR[A](xs: List[A]): List[A] =  
  17.   xs.foldRight(List[A]()) { (x, acc) =>  
  18.     if (acc.isEmpty || acc.head != x) x :: acc  
  19.     else acc  
  20.   }  
  21.   
  22. // :\ (FoldRight)  
  23. def compressFildR2[A](xs: List[A]): List[A] =  
  24.   (xs :\ List[A]()) { (x, acc) =>  
  25.     if (acc.isEmpty || acc.head != x) x :: acc  
  26.     else acc  
  27.   }  

Saturday, October 30, 2010

S07

P06はしょうもないので省略。

S-99: Ninety-Nine Scala Problems
を試してみる。

  1. // P07 (**) Flatten a nested list structure.  
  2. // Example:  
  3. // scala> flatten(List(List(1, 1), 2, List(3, List(5, 8))))  
  4. // res0: List[Any] = List(1, 1, 2, 3, 5, 8)  
  5.   
  6. def flatten(xs: List[Any]): List[Any] = {  
  7.   def recursive(rest: List[Any], result: List[Any]): List[Any] = rest match {  
  8.     case Nil => result  
  9.     case head :: tail =>   
  10.       head match {  
  11.         case Nil => recursive(tail, result)  
  12.         case h :: t => recursive(tail, recursive(t, recursive(List(h), result)))  
  13.         case notaList => recursive(tail, result ::: List(notaList))  
  14.       }   
  15.     case notaList => result ::: List(notaList)  
  16.   }  
  17.   recursive(xs, Nil)  
  18. }  

解答例
ちくしょー!反則だ(笑

S05

S-99: Ninety-Nine Scala Problems
を試してみる。

// P05 (*) Reverse a list.
// Example:
// scala> reverse(List(1, 1, 2, 3, 5, 8))
// res0: List[Int] = List(8, 5, 3, 2, 1, 1)

  1. def builtIn[T](xs: List[T]): List[T] = xs.reverse  
  2.   
  3. def recursive[T](xs: List[T]): List[T] = xs match {  
  4.   case Nil => xs  
  5.   case h :: tail => recursive(tail) ::: List(h)  
  6. }  
  7.   
  8. // 末尾再帰版  
  9. def tailRecursive[T](xs: List[T]): List[T] = {  
  10.   def recursive[T](rest: List[T], result: List[T] ): List[T] = rest match {  
  11.     case Nil => result  
  12.     case h :: tail => recursive(tail, List(h) ::: result)  
  13.   }  
  14.   recursive(xs, Nil)  
  15. }  

解答例
foldLeftってのがあったか!

  1. def foldLeft[T](xs: List[T]): List[T] =   
  2.   xs.foldLeft(List[T]()){(r, h) => h :: r}  

S04

S-99: Ninety-Nine Scala Problems
を試してみる。

  1. //P04 (*) Find the number of elements of a list.  
  2. //Example:  
  3. //scala> length(List(1, 1, 2, 3, 5, 8))  
  4. //res0: Int = 6  
  5.   
  6. def lengthBuiltIn[T](xs: List[T]): Int = xs.length  
  7.   
  8. // 末尾再帰版  
  9. def lengthTailRecursive[T](xs: List[T]): Int = {  
  10.   def recursive(l: List[T], n: Int): Int = l match {  
  11.     case Nil => 0  
  12.     case _ :: Nil => n + 1  
  13.     case _ :: tail => recursive(tail, n + 1)  
  14.   }  
  15.   recursive(xs, 0)  
  16. }  
  17.   
  18. def length[T](xs: List[T]): Int = {  
  19.   def recursive(l: List[T]): Int = l match {  
  20.     case Nil => 0  
  21.     case _ :: tail => 1 + recursive(tail)  
  22.   }  
  23.   recursive(xs)  
  24. }  

解答例

Thursday, October 28, 2010

S03

S-99: Ninety-Nine Scala Problems
を試してみる。

// P03 (*) Find the Kth element of a list.
// By convention, the first element in the list is element 0.
//
// Example:
// scala> nth(2, List(1, 1, 2, 3, 5, 8))
// res0: Int = 2

  1. def nth[T](n: Int, xs: List[T]): T = xs match {  
  2.   case Nil => throw new NoSuchElementException  
  3.   case _ if(n < 0 || xs.length <= n) => throw new IllegalArgumentException  
  4.   case h :: _ if(n == 0)=> h  
  5.   case _ :: tail => nth(n - 1, tail)  
  6. }  

解答例はタプルにしてmatch-caseしてる。

S02

S-99: Ninety-Nine Scala Problems
を試してみる。

P02 (*) Find the last but one element of a list.
Example:
scala> penultimate(List(1, 1, 2, 3, 5, 8))
res0: Int = 5

  1. def penultimate[T](xs: List[T]): T = xs match  {  
  2.   case x :: _ :: Nil => x  
  3.   case _ :: tail => penultimate(tail)  
  4.   case _ => throw new Exception("no such element")  
  5. }  

  1. def lastNthBuiltln[A](n: Int, ls: List[A]) = {  
  2.   if(n <= 0throw new IllegalArgumentException  
  3.   if(ls.size < n) throw new NoSuchElementException  
  4.   ls.takeRight(n).head  
  5. }  
  1. def lastNth[A](n: Int, ls: List[A]): A = {  
  2.   if(n <= 0throw new IllegalArgumentException  
  3.   if(ls.size < n) throw new NoSuchElementException  
  4.   ls match {  
  5.     case xs if(ls.length == n) => xs.head  
  6.     case _ :: tail => lastNth(n, tail)  
  7.     case Nil => throw new NoSuchElementException  
  8.   }  
  9. }  

S01

S-99: Ninety-Nine Scala Problems
を試してみる。

とりあえず、P01を試してみた。
P01 (*) Find the last element of a list.
Example:
scala> last(List(1, 1, 2, 3, 5, 8))
res0: Int = 8

  1. def last[T](xs: List[T]): T = xs match {  
  2.     case h :: Nil => h  
  3.     case _ :: tail => last(tail)   
  4.     case _ => throw new NoSuchElementException  
  5.   }  

Thursday, July 29, 2010

Rubyの特異メソッドと特異クラス

プログラミング言語Ruby P269辺りに特異メソッドと特異クラスについての解説がある。
読んだだけじゃ絶対にわすれるので、メモっとく。

特異メソッド
クラスに属するすべてのオブジェクトではなく、単一のオブジェクトだけのために定義されたメソッド
オブジェクトの特異メソッドは、そのオブジェクトのクラスによって定義されない。
そのオブジェクトに対応付けられた無名の特異クラスのインスタンスメソッドである。
無名の特異クラスのことをシングルトンクラス、メタクラスと呼ぶ。

各インスタンスごとに特異クラスを持つ。
classのインスタンスClass1の特異メソッドは、Class1クラスのクラスメソッドであり、
classのインスタンスであるClass1の特異クラスのインスタンスメソッドである。

試してみた。

  1. # ClassクラスのインスタンスであるPointオブジェクトに特異メソッドを定義  
  2. # Pointクラスのクラスメソッドになる  
  3. class Point; end  
  4. def Point.sum x, y; x + y; end  
  5. p Point.sum 1,2  #=> 3  
  6.   
  7. # 特異メソッドを複数定義時に便利な構文糖  
  8. class << Point  
  9.   def minus x, y; x - y; end  
  10.   def multi x, y; x * y; end  
  11. end  
  12. p Point.minus 1,2  #=> -1  
  13. p Point.multi 1,2  #=> 2  
  14.   
  15. # クラス定義中にクラスメソッドを複数定義するときに便利な構文糖  
  16. # class << self は特異クラス(classのインスタンスであるPointクラスオブジェクト)  
  17. class Point  
  18.   class << self  
  19.     def div x, y; x / y; end  
  20.   end  
  21.   def self.eignclass   
  22.     class << selfselfend  
  23.   end  
  24. end  
  25.   
  26. # p1オブジェクトの特異メソッドを定義  
  27. p1 = Point.new  
  28. def p1.sum x, y, z; x + y + z; end  
  29. p p1.sum(1, 2, 3) #=> 6  
  30.   
  31. # p2からはp1の特異メソッドは見えない  
  32. p2 = Point.new  
  33. #p p2.sum(1, 2, 3) #=> NoMethodError  
  34.   
  35. class << p2  
  36.   def sum x, y ,z, a; x + y + z + a; end  
  37.   def multi x, y ,z, a; x * y * z * a; end  
  38. end  
  39. p p2.sum 1, 2, 3, 4 #=> 10  
  40. p p2.multi 1, 2, 3, 4 #=> 24  
  41.   
  42. # p2からはP1特異メソッド特異メソッドは見えない  
  43. #p p1.sum 1, 2, 3, 4 #=> NoMethodError  
  44.   
  45. # 実行結果  
  46. # 3  
  47. # -1  
  48. # 2  
  49. # 6  
  50. # 10  
  51. # 24  

もう一丁。

  1. class Class1  
  2.   puts "#{self.__id__} before open singleton class"  
  3.   class << self  
  4.     puts "#{self.__id__} opening singleton class"  
  5.   end  
  6.   def self.eignclass   
  7.     class << selfselfend  
  8.   end  
  9.   puts "<<< " + self.to_s  
  10. end  
  11.   
  12. class Class2  
  13.   puts ">>> " + self.to_s  
  14.   puts "#{self.__id__} before open singleton class"  
  15.   class << self  
  16.     puts "#{self.__id__} opening singleton class"  
  17.   end  
  18.   def self.eignclass   
  19.     class << selfselfend  
  20.   end  
  21.   puts "<<< " + self.to_s  
  22. end  
  23. puts "------------"  
  24. puts "#{Class1.__id__} Class1.__id__"  
  25. puts "#{Class1.eignclass.__id__} Class1.eignclass.__id__"  
  26.   
  27. puts "------------"  
  28. puts "#{Class2.__id__} Class2.__id__"  
  29. puts "#{Class2.eignclass.__id__} Class2.eignclass.__id__"  
  30.   
  31. puts "------------"  
  32. c1 = Class1.new  
  33. puts "#{c1.__id__} c1's id"  
  34. class << c1   
  35.   puts "#{self.__id__} c1's singleton class"  
  36. end  
  37.   
  38. puts "------------"  
  39. c11 = Class1.new  
  40. puts "#{c11.__id__} c11's id"  
  41. class << c11  
  42.   puts "#{self.__id__} c11's singleton class"  
  43. end  
  44.   
  45. puts "------------"  
  46. c2 = Class2.new  
  47. puts "#{c2.__id__} c2's id"  
  48. class << c2   
  49.   puts "#{self.__id__} c2's singleton class"  
  50. end  
  51.   
  52. puts "------------"  
  53. c21 = Class2.new  
  54. puts "#{c21.__id__} c21's id"  
  55. class << c21  
  56.   puts "#{self.__id__} c21's singleton class"  
  57. end  
  58.   
  59. # 実行結果  
  60. # >>> Class1  
  61. # 70227334526040 before open singleton class  
  62. # 70227334526020 opening singleton class  
  63. # <<< Class1  
  64. # >>> Class2  
  65. # 70227334525980 before open singleton class  
  66. # 70227334525680 opening singleton class  
  67. # <<< Class2  
  68. # ------------  
  69. # 70227334526040 Class1.__id__  
  70. # 70227334526020 Class1.eignclass.__id__  
  71. # ------------  
  72. # 70227334525980 Class2.__id__  
  73. # 70227334525680 Class2.eignclass.__id__  
  74. # ------------  
  75. # 70227334525100 c1's id  
  76. # 70227334525040 c1's singleton class  
  77. # ------------  
  78. # 70227334524940 c11's id  
  79. # 70227334524880 c11's singleton class  
  80. # ------------  
  81. # 70227334524780 c2's id  
  82. # 70227334524720 c2's singleton class  
  83. # ------------  
  84. # 70227334524620 c21's id  
  85. # 70227334524560 c21's singleton class  

Thursday, July 22, 2010

Rubyのクラスメソッド

プログラミング言語Ruby(P268)

クラスのクラスメソッドとは、そのクラスを表現するClassクラスのインスタンスの特異メソッドにすぎない。

RubyのModule, Class, include, extend, selfポインタ

プログラミング言語Ruby P258の内容のサンプル。

クラス階層が必要のないグローバル関数を、グローバルな名前空間を汚さないためにModuleとしてまとめる方法。
moduleに定義したインスタンスメソッドをmix-inする方法( include, extend)
includeはインスタンスメソッドとして織りまぜ、
extendは特異メソッドとして織りまぜる。

  1. module SampleModule  
  2.   
  3.   # class method  
  4.   def self.hello  
  5.     puts "hello"  
  6.   end  
  7.   
  8.   # class method  
  9.   def self.goodby  
  10.     puts "goodby"  
  11.   end  
  12.   
  13.   # instance method  
  14.   def good_morning  
  15.     puts "good_morning"  
  16.   end  
  17. end  
  18.   
  19. class IncludeMod  
  20.   # インスタンスメソッドとしてinclude  
  21.   include SampleModule  
  22. end  
  23.   
  24. class ExtendMod  
  25.   # クラスメソッドとしてextend  
  26.   # この時のselfはクラスの中、メソッド定義の外なので ExtendModクラスをサス(P225)  
  27.   self.extend SampleModule  
  28.   #ExtendMod.extend SampleModule  
  29. end  
  30.   
  31. SampleModule.hello  
  32. SampleModule.goodby  
  33.   
  34. IncludeMod.new.good_morning  
  35. ExtendMod.good_morning  

Rubyの継承時のprivateメソッドには注意

プログラミング言語Ruby P248

サブクラスはPrivateメソッドを継承する。
サブクラスは親で定義されたprivateメソッドを呼び出せ、オーバーライドすることが可能。

他人が書いたクラスをサブクラス化するときは気をつけろ。
偶然、同じ名前のprivateメソッドをオーバーライドするとバグる。

Rubyではサブクラス化するのは、スーパークラスの実装を欲知っている時に限るべきだ。
継承ではなく、委譲するべき。

Ruby1.9からSymbolクラスにto_procが追加されたってか

プログラミング言語Rubyを読んでいる。
P217に、Ruby1.9からSynbolクラスにto_procが追加されたので、シンボルに&プレフィックスを付けると、イテレータにブロックとして渡せるようになった、と書いてある。

メモメモ。

  1. def succ x; x + 1; end  
  2. p [1,2,3].map{|x| x + 1}  
  3. p [1,2,3].map{|x| succ x}  
  4. p [1,2,3].map(&:succ)  
  5. p [1,2,3].map(&self.method(:succ))  
  6. p [1,2,3].map{|x| self.method(:succ).call(x) }  
  7. p [1,2,3].map{|x| self.method(:succ).to_proc.call(x) }  

Wednesday, July 21, 2010

Rubyで関数を継承?

勉強のためにRubyのライブラリでも見ていくことにした。
とりあえず一発目はtempfile.rbでも見てみるかということで、13行目。

  1. class Tempfile < DelegateClass(File)  
ほうほう、DelegateClassを継承しているのね。でも括弧なんだろ? おもむろにCtagsで飛んでみた。(delegate.rb) そしたら、ビックリ。
  1. def DelegateClass(superclass)  
関数じゃないですか。

分からん。。
また分かったら追記するってことでメモっておく。

追記
わかった。
def DelegateClass(superclass)
はクラスを返すメソッドなのね。

Delegate(クラス)で指定したクラスのpublic instance methodと
__getobj__, __setobj__をmodule_evalしたクラスを
継承したいからこんなことしてるのか。

Thursday, July 1, 2010

vrome 0.5.7 (chrome extention)でページ内日本語検索ができんぞ

/(スラッシュ)でページ内を日本語で検索しようとしても検索できない。
アルファベットならいけるけど。
Ctrl + fもnext pageに割り当ててられていて使えない。

不便過ぎて発狂しそうになったので、extentionのソースを変更してCtrl + f でChromeの検索窓が出るようにした。


kanbe@kanbe-laptop% locate vrome
/home/kanbe/.config/google-chrome/Default/Extensions/godjoomfiimiddapohpmfklhgmbfffjj/0.5.7/vromerc_example

kanbe@kanbe-laptop% cd /home/kanbe/.config/google-chrome/Default/Extensions/godjoomfiimiddapohpmfklhgmbfffjj/0.5.7
kanbe@kanbe-laptop% grep "<c-f>" **/*
frontend/main.js:  add("<c-f>" , Scroll.nextPage     );
..




main.jsのadd...をコメントアウトで終了。

Tuesday, June 29, 2010

VirtualBox上のWin7でiPhoneをiOS4にUpdateしたらハマった



ubuntu10.04上のVirtualBox3.2でwindows7を動かしており、その上でiTunes9を使って、iPhone3GSをiOS4にupdateしようとしたら、ハマった。

updateしながら寝て、起きたらiPhoneの画面にiTunesへつなげろっていう画像が表示されており、iPhoneがVirtualBoxに認識されない。
VirtualBoxの右下のUSBボタンをクリックすると、iPhone (Recovery mode)とか表示されており、グレーアウトされてマウスで選択できない。

アイヤー、困っちゃったよ〜!! 仕事いかなきゃならん。

と思いつつもググったらみんなハマってます。


Originally Posted by LarryJ2 
1. IF USB device doesn't appear to the guest OS and is unavailable inside the guest OS.

2. and/or IF In the Guest window, under Devices->USB Devices, your USB devices appear but are grayed out...

3. Try this:
  1. In the host (Karmic 9.10 for example), System->Administration->Users and Groups
  2. Click on the Keys Icon (to right of Help) and give your password.
  3. Select (highlight) your normal user line (the one with /home/xxx)
  4. Click Manage Groups.
  5. In the Groups settings List Box, navigate down to vboxusers
  6. With vboxusers high lighted, click properties
  7. Click the check box next to your normal user to indicate you want the normal user to be a member of the vboxusers group.
  8. reboot the host.
↑と、
http://forums.virtualbox.org/viewtopic.php?f=2&t=18852
I had originally set a USB filter for the iPhone based on the VendorID and the ProductID. 
これを参考に、VirtualBoxのUSBフィルタ設定に新規追加して、以下を設定。

  • ベンダIDに05ac
  • メーカーにApple Inc.

そんでVirtualBoxを再起動してみたら、Virtualbox右下のUSBのグレーアウトだったiPhoneが選択できるようになり、VurtualBox上のWin7から見えるようになりました。

それからiTunes上で復元ボタンを押すしかなくて、工場出荷状態になって超焦ったけど、iOS4が入った後にiTunes上で、バックアップから復元したらデータは元通りになりました。

焦ったよ、ジョブズ君。

Monday, June 28, 2010

vrome - Vim keybindings extension for chrome を試す

そろそろ、ブログでも書いてみるかということで、bloggerに登録後、さぁ書こうと思ってさ、
しばらく、ブラウザのテキストエリアに直接書き込んでたんだけど、途中で泣きそうになりました。

僕、Vimで書きたいです。

ということでGoogle Chromeの拡張機能である、Vromeを試してみたのでメモっておきます。
やりたいことは、Chromeのテキストエリアから外部エディタ(Vimとか)を立ち上げて、文字を書いて、:wqとするとテキストエリアに反映されること。

- 手順
1. Google Chrome上でVrome(最新版0.5.7 2010/6/28時点)をインストール

2. ここを見て、上から順番に実行していく。
$ sudo apt-get install ruby ruby1.8-dev rubygems rails
 $ sudo gem install json
 $ sudo gem install vrome -s http://rubygems.org

3. ~/.vromercを配備 サンプル

4. 起動してみる
/var/lib/gems/1.8/gems/vrome-1.0.0/bin/vrome

↓こんなエラーが出た場合は、
kanbe@kanbe-laptop% /var/lib/gems/1.8/gems/vrome-1.0.0/bin/vrome 
 /var/lib/gems/1.8/gems/vrome-1.0.0/bin/../lib/server.rb:4:in `require': no such file to load -- json (LoadError)
   from /var/lib/gems/1.8/gems/vrome-1.0.0/bin/../lib/server.rb:4
   from /var/lib/gems/1.8/gems/vrome-1.0.0/bin/vrome:4:in `load'
   from /var/lib/gems/1.8/gems/vrome-1.0.0/bin/vrome:4

/var/lib/gems/1.8/gems/vrome-1.0.0/lib/server.rb の先頭に、以下を追加。
require 'rubygems'

5. ~/.profileとかに以下を追記
nohup /var/lib/gems/1.8/gems/vrome-1.0.0/bin/vrome > /dev/null &

これで、テキストエリアで<Ctrl-i>とするとgvimが立ち上がり、
:wqとするとgvimの内容が反映されるようになります。

# ブラウザのプロキシ設定で127.0.0.1を除外するのをお忘れなく。

ちょっと試した感じ、Vrome使いやすそうですね。
しばらく使ってみよっと。