Scala-tutorial.pdf

みずしまさん作成のScala-tutorial.pdf資料を見たがよくまとまっており非常に分かりやすい。しかし、ScalaJavaRuby、関数言語(HaskellOCamlなど)が好きな人は親近感を覚える言語ではないかと思った。C++Pythonが好きな人は毛色が違う言語である気がした。


高階関数(3)」のopen関数の例で、引数の()が2つあるのはどういう意味になるのだろう?foo(a :Int)が、(Int => Int)型の関数を返すのだろうか?

scala> def foo(a :Int)(b :Int) = {a + b}
foo: (Int)(Int)Int

scala> def bar(a :Int, b :Int) = {a + b}
bar: (Int,Int)Int

scala> foo(1)(2)
res0: Int = 3

scala> bar(1, 2)
res1: Int = 3

ここで、bar(1)と呼び出すと引数の個数が不足しているので、Haskellのように自動的にカリー化されずエラーが発生する。ここでのfooはfoo(1)(2)のように呼び出し、barはbar(1, 2)のように呼び出すので同じものを表している訳ではない。()と,を省略した、foo 1 2もエラーだし、bar 1 2もエラーとなる。つまり、fooとbarを同様に扱えない。同様に扱うにはどうすれば良いのだろう?


Haskellでは以下のように関数呼び出しの()を省略可能で、しかも自動的にカリー化されるので、上記のfooとbarのような区別はないと思われる。

foo a b = a + b
bar = foo 1

main = print $ bar 2

--実行結果
3


追記(2008/5/13):

みずしまさんにコメントで教えて頂いたので整理。

// Haskell
// foo :: a -> a -> a
// foo a b = a + b

// Scala
// (Int) => (Int) => Int
def foo(a :Int)(b :Int) = a + b
// Haskell
// bar :: (a, a) -> a
// bar (a, b) = a + b

// Scala
// (Int, Int) => Int
def bar(a :Int, b :Int) = a + b
// Haskell
// foo a b = a + b
// foo2 = foo 1
// print $ foo2 2

// Scala
val foo2 = foo (1) _
println(foo2(2))

Scalaの方は構文に癖があるけど、それなりの理由があるはず。とりあえずScalaは、引数で与える個数を間違えた場合はエラーが出てくれるので安全かも。