Scala School (1)
朝は脱線したのでちゃんと項目をおっかけてみます。今日のテキストは以下。
Expressions
REPL に 1 + 1 という式を食わせています。
scala> 1 + 1 res0: Int = 2
すると REPL は Scala の式を結果として出力するんですね。res0 という名前の Int 型な変数に 2 が格納されてます、という事か。ちなみに res0 を REPL に食わせるとどうなるかというと
scala> res0 res1: Int = 2
今度は res1 ができるんですね。このあたり何となく微妙なカンジですが。
Values
式の結果に名前を付けることができますよ、とのこと。
scala> val two = 1 + 1 two: Int = 2
こうすれば自動で res* みたいなソレは作成されない模様。ちなみに val というシンボルの束縛を変更することは無理みたいです。
scala> val val = 1 + 1 <console>:1: error: illegal start of simple pattern val val = 1 + 1 ^
成程。てか、val は const で var が変更可能な、らしい。いっちゃん下で気づいてたりして。。
Variables
変数に束縛されてる値の変更について
scala> var name = "steve" name: java.lang.String = steve scala> name = "marius" name: java.lang.String = marius
Functions
手続き? 関数? 最初に出てくるのは def で function を作れます、という件。
scala> def addOne(m: Int): Int = m + 1 addOne: (m: Int)Int
これって
- addOne って名前の
- 引数一つ、m という名前で Int 型
- 戻りは Int 型
- 手続きとしての式は m + 1 の結果を戻す形 (日本語変ですね)
という意味の式を REPL に食わせているのか。む、つーことは朝ハマッた高階関数な定義は以下なカンジで良いのかな。
scala> def addN (n: Int): (Int) => Int = (x: Int) => { x + n } addN: (n: Int)Int => Int scala> var add3 = addN(3) add3: Int => Int = <function1> scala> add3(4) res3: Int = 7
ビンゴなのかな。def で手続きの名前を書いて
- 引数一つで名前が n で Int 型
- Int な引数を取って Int な値を戻す手続き型のオブジェクト (?) を戻す
- 戻すのは手続きオブジェクト
成程。すばらです。元に戻すと次に以下を実行してます。
scala> var three = addOne(2) three: Int = 3
addOne(2) という式を評価してその結果が three という変数に束縛される、という形ですね。最後に引数が無い手続きの定義の例が挙げられています。
scala> def three() = 1 + 2 three: ()Int
こんな形で手続き定義もできるのか。引数だけではなくて戻り値の型の記述も略されていますが Int 型と判断してくれています。自動で判断してるのかな。
scala> def marius() = "marius" marius: ()java.lang.String
これはまた。以降に出ている例は定義した手続きを呼び出す式を REPL に食わせて戻された値が自動でアサインされる変数に束縛されている様子が確認できます。
次は lambda ですね。好きです。
Anonymouns Functions
無名手続きを生成できます、とのこと。無名手続きを REPL に食わせると手続きオブジェクトを作って自動で生成される変数に束縛、となる模様。
scala> (x: Int) => x + 1 res2: Int => Int = <function1>
手続きとしては引数に 1 を加えて戻すものになってます。
scala> res2(1) res3: Int = 2
なんとなく REPL の挙動にも慣れてきたカンジ。次は無名手続きなオブジェクトを変数に束縛させております。
scala> val addOne = (x: Int) => x + 1 addOne: Int => Int = <function1>
あ、これは addOne という変数に無名手続きなオブジェクトを代入してるのか。さっきの高階関数の例でも無名手続きを戻す、という形になっていますね。
addOne には手続きオブジェクトが束縛されているので手続き呼び出しな式を REPL に食わせてあげると結果が出力されます。
scala> addOne(1) res4: Int = 2
あるいは、手続きがたくさんの式で構成される場合は {} 使ってね、とのこと。そしてこれは無名手続きでも同様、てなんか微妙な書き方ですね。
scala> { i: Int => println("hello world") | i * 2 | } res5: Int => Int = <function1>
引数を取る無名手続きの記述としてしばしば出てくるよ、と書いてあります。手続き呼び出しを REPL に食わせるとこんなカンジ。
scala> res5(1) hello world res6: Int = 2
Partial application
partially apply って凄い。しかも引数はどれでも可能とか書いてありますね。
scala> def adder(m: Int, n: Int) = m + n adder: (m: Int, n: Int)Int
手続きを定義して部分適用したら手続きオブジェクトが戻るみたい。
scala> var add2 = adder(2, _:Int) add2: Int => Int = <function1>
戻ってきた (出力された) 式の意味が微妙。あ、この表現は引数を取る無名手続き云々な式を REPL に食わせて戻ったソレと同様ですね。式の意味合いてきには
- add2 という名前に
- Int な引数一つ
- Int な戻り
- という手続きオブジェクトが束縛
ということになるのか。function1 というのは 1 引数の手続きオブジェクトの何やら、というソレを見たんですがここではスルー。
ちょっと連続で色々ヤッてみます。
scala> add2(3) res7: Int = 5 scala> add2 = adder(_:Int, 2) add2: Int => Int = <function1> scala> add2(3) res8: Int = 5
すげー、とか思ったんですが curried なんていうソレがあることもあり、このあたりの評価は柔軟なんですかね。
あら?
var と val の違いが分からんぞ。あ、val なら束縛は変えられなくて、var なら大丈夫ってことなのか。成程orz
続きはまた明日。