初學 functional programming

初學 Scala,限定只能使用 functional 以及 immutable 時,被卡在以下問題:

1
2
3
4
5
/**
* This function should return the first position of character `c` in the
* 2 dimensional vector `v`.
*/
def findChar(c: Char, v: Vector[Vector[Char]]): Option[(Int, Int)] = ???

看起來真夠簡單,但想不出怎麼回傳第二層的 indexOf 值。第一版是這樣寫的:

1
2
3
4
5
6
7
8
9
10
11
def findChar(c: Char, v: Vector[Vector[Char]]): Option[(Int, Int)] = {
var y = -1
val x = v.indexWhere(vv => {
y = vv.indexOf(c)
y > -1
})
if (x > -1)
Some((x, y))
else
None
}

這樣是不差啦,但就是多了個 var y。自己硬寫的結果是這樣:

1
2
3
4
5
6
7
def findChar(c: Char, v: Vector[Vector[Char]]): Option[(Int, Int)] = {
val x = v.indexWhere(_.indexOf(c) > -1)
if (x > -1)
Some((x, v(x).indexOf(c)))
else
None
}

用了兩次 indexOf 實在有夠難看。最後忍不住 Google:

1
2
3
4
5
6
7
def findChar(c: Char, v: Vector[Vector[Char]]): Option[(Int, Int)] = {
val r = v.map(_ indexOf c).zipWithIndex.find(_._1 > -1)
r match {
case Some((x, y)) => Some((y, x))
case None => None
}
}

但找到以後馬上結束就好,map 會轉換整個 Vector,其實是多的,還是感覺有點硬寫。

感想是:

  1. 要記得有 zip 這類東西。
  2. 思考方式還是偏 imperative.

另外一個大問題就是如果自我要求每個 recursive 都要是 @tailrec tail recursive 也是很障礙。