Scalaの初学者が文法で混乱した箇所


ちょっと twitter で文法の話とか難しさの話とかを見たので、思い出して書いてみる。
チラ裏的なそんな何か。
そもそも今も別に業務で使ったりしてないので scala スキルは別に全然ないから、全く大した話はできない。

脱初学者が超初学者の助けになれば良いな、というユルい感じでお願いします。

## 背景
なんかプログラマになって2年目くらいで触った気がする。
当時は php だけ知ってか、python もちょっと触ってたか、というくらい。
java の経験はなかった。
あぁ、javascript と jQuery はあった。（今思うと全然わかってなかったけど）

java と scala の違いという趣旨の本を読みながら写経したけど、「そもそも java シラネー」って思いながら読んでた。
「へー、java って php と違って`__construct`じゃあないんだ...」ってレベル。

## scala でつまずいた箇所
「なんか省略できるっぽい、記号が多い」って印象がほとんどだったと思う。
`Option`とか`match-case`は全然知らなかったので「へー...??」って流してたので、つまずいたとかではない。
`static`や`enum`は当時は「同じ事が出来るけど書き方が違う」と思っていたので、都度 gg っていたのでつまずいた覚えはない。

具体的にはほとんどが`class`の中に書いたりする`def`の部分と、あとちょっとが`_`とか`it`とか`=>`とかだった気がする。

## 具体的に
実はもう何がわからなかったのかわからないのだけれど、こんなんだった気がするという感じで整理してみる。

### 普通の変数宣言
変数名と型があって、右辺に値がある一番シンプルな例
型の有無は違うけど、これは php と似てた気がしたので平気だった

```Scala
def name: String = "john"
```

### 型は省略可能
明らかな場合は省略できるらしい
まだ平気

```Scala
def name = "john"
```

### メソッド定義
なんか引数とか戻りとかが逆で気持ち悪いなー
けどまぁそういう決まりだし、慣れるしかない
けどなんか`=`入ってるのが気持ち悪いなー

って思った

なんで`=`が気持ち悪いと思ったかはもう思い出せないけど、多分「メソッドは`function`で宣言する特別な何か」で「`=`使うのはただの変数に使うやつ」とか思ってたんじゃあないかな

```Scala
def add(x: Int, y: Int): Int = {
    x + y
}
```

### `{ }`が省略できるらしい
「本文が１行なら`{ }`は省略できる」とか見たんだっけかなぁ
この辺から「えーなにそれ、なんで１行だと特別扱いしてんの」ってくらいに思ってた

```Scala
def add(x: Int, y: Int) = x + y
```

それと、あと上で似たこと書いたけど「`=`は変数への代入に使うもの」だと思っていたので、`=`より左に`( )`があることが気持ち悪かった気がする

### `=>`出現
この辺から記述の切れ目がどこだかさっぱりわからなくなる
`=>`と`=`を「どっちが右か」とかで把握しようとしてると多分この辺で限界が来るんだと思う

コンパイルが通るまで適当にいじってみるけど、`f:`の型注釈と`x:`の型注釈の違いを理解していない

```Scala
def f: (String => String) = x => x + "!"
```

```Scala
def f = (x: String) => x + "!"
```

あとこれはどうして定義するときに`f`なのに、呼ぶときは`f("hello")`みたいに`( )`が出てくるのかもよく分かってない
`( )`が出来るのは`add(x: Int, y: Int)`みたいにした時だけじゃあないのか？

### どこからともなく現れる恐いお兄さんたちが残していった呪文
理解するのを放棄

```Scala
def f(s1: String): (String => String) = s2 => s1 + " " + s2
```

ちなみに、どう実行するのかもわからない

### 引数がないと呼ぶときの`( )`は省略できる
```Scala
def f(): String = {
    "hello"
}
```

これは呼ぶときに`f`でも`f()`でも良い

```
scala> f
res8: String = hello

scala> f()
res9: String = hello
```

なのに下の例（再掲）は定義に`( )`はなかったのに、`( )`を付けなければいけなかった
何が省略できるのかさっぱりわからない

```Scala
def f = (x: String) => x + "!"
```

### つまずき方のまとめ
こうして振り返ると、見知らぬ記述があったときに「この場合は`=`より左に`( )`が書ける」とか「〜の場合は〜が省略できる」みたいに場当たり的に理解していたのですぐ限界が来た感じがする。

## じゃあどうするのか
実はここから先をどうしようかとても困っている。
僕は結局 scala は「んー、scala じゃあないと出来ないこと今はないし、いーや」って思ってこの後ずっと触ってなかった。

んだけど、色々彷徨っている間に haskell をやって、ある程度 haskell がわかってからもう一度 scala 見てみたら上の問題は全部一発で理解できた。
だからと言って今困っている人に「 haskell やれ」じゃあ身も蓋もないので、ちょっと簡単に考えてみようかなと思う。

本当今思いつきで書くので全然程度は高くないです。

### とりあえず右と左に分けて考える
`( )`とか`{ }`とか`=>`とかあるけど、一番ポイントなのは`=`だと思います。
上の例って全部「`=`が1つ」だと思います。

なので超雑におっきくまとまりで捉えると、こうなってると思います。

```Scala
def 左 = 右
```

### 左
左は定義と捉えると良いと思います。

変数の名前やメソッドの名前です。
それから型注釈は定義部に入ります。

```Scala
def f(s1: String): (String => String) = s2 => s1 + " " + s2
```

先ほど上げた僕が理解を放棄した例です。

`=`より左が定義部です。
その定義部は`f(...)`と`fの型注釈`に分けて捉えれば良さそうです。

`f`の引数が`String1つ`で、`f`の戻りの型は`String => String`です。

ただ1行を眺めると`=`や`( )`がいくつか目に入りますが、最初に見るべきはこの様に`=`の左側で良いと思います。

### 右
対して右は値と捉えれば良いと思います。

`= 5`だったり、`= return "John"`だったり、`= { 複数行 }`だったりします。

ところで`return`は省略出来ますので、`= 5`は`= return 5`とも捉えられます。
さらに1行の場合は`{ }`も省略出来るので、`= 5`は`= { return 5 }`と捉えられます。

こうして考えると、`= 5`も`= { 複数行 }`も同じだと思えませんか？

また、値として扱えるのは`5`や`"John"`だけではありません。

```Scala
def f: (Int => Int) = x => x + 2
```

この様に`f`という変数に`x => x + 2`という処理を束縛出来ます。
ですので`f`の値は`x => x + 2`です。

```Scala
def f: (Int => Int) = {
    return x => x + 2
}
```

こうして見れば値部分は`= 5`も`= { 複数行 }`も`=>`が入ってるのも文法的には全部同じだと思える様になると思います。

もう一度先ほどのややこしい例をあげます。

```Scala
def f(s1: String): (String => String) = s2 => s1 + " " + s2
```

（もしくは区切りが欲しければこう読み替えても良い）

```Scala
def f(s1: String): (String => String) = {
    return s2 => s1 + " " + s2
}
```

`f`の型注釈の`String => String`と`return`部を見ると、値は`s2 => s1 + " " + s2`の部分です。
そして`s1: String`を受けたらそれを返すのが`f`ですね。

`f`に`String`を渡すと`String => String`が得られるので、以下の様に使います。

```
scala> f("Hello")("John")
res15: String = Hello John

scala> f("Hello")("Jane")
res16: String = Hello Jane
```

（おまけ　`f(...)(...)`が何の役に立つのか）
`s2 => s1 + " " + s2`が値として`return`出来ると言うことは、それを変数に受けることも当然可能ですよね。
なのでこういう事も出来ます。

```
scala> def greeting = ???   // 時間によって f("Hello") か f("Good night") が実行される何か
greeting: String => String

scala> greeting("John")
res17: String = Hello John

scala> greeting("Jane")
res18: String = Hello Jane
```

例えばまず「環境毎に異なる設定ファイルパスを指定して」次に「本当にやりたい処理を指定する」みたいに、段階を踏んだ処理を分離して記載したり出来ます。

### 他
今ざっと昔混乱した記述を見返していて、あと１つちょっと別に理解しておいた方が良いことがあったので、それだけ書いておしまいにします。

```Scala
def f1(): String = {
    "hello"
}
```

```
scala> println(f1)
hello

scala> println(f1())
hello
```

`f1()`で定義しているこれは`( )`の省略が可能で、

```Scala
def f2 = (x: String) => x + "!"
```

```
scala> println(f2)
<function1>

scala> println(f2("foo"))
foo!
```

こっちは`f2`で定義してるのに`( )`の省略が不可能、という話について。
さっきの`f("Hello")("Jane")`の例もそうだけど、自分が何に`( )`を付けているのかを理解しながら読み書きする癖を付けると良いと思います。

`f1`の方は`f1()`に引数が必要なく、値部は`"hello"`なので`f1()`を実行すると`"hello"`という文字列が得られます。
対して`f2`の方は`f2`という変数の中身が`x => x + "!"`という処理なので、そいつに対して`("foo")`をしています。
ついでに言うと`f("Hello")("Jane")`は`s2 => s1 + " " + s2`を手に入れるために`("Hello")`をして、手に入ったそれを実行するために`("Jane")`しています。

この様に「何に対する`( )`か」を考えると理解度がぐっとあがるんじゃあないかな、と思います。
イメージとしては`f`を実行するために`( )`を付けるのか、`f`の中に入ってる処理のために`( )`と言った感じ？

### BNF
ブロックで捉えるというのは BNF [(wiki)](https://ja.wikipedia.org/wiki/%E3%83%90%E3%83%83%E3%82%AB%E3%82%B9%E3%83%BB%E3%83%8A%E3%82%A6%E3%82%A2%E8%A8%98%E6%B3%95) を見るともっと厳密に学習できます。
https://www.scala-lang.org/files/archive/spec/2.12/13-syntax-summary.html

興味があれば覗いてみると良いと思います。`def`で文字列検索してそこから辿ると関連したのが見つかりそう。

最近わけあって java のはじっくり見てたけど、scala のは初見。雰囲気全然違うなぁ。

## おしまい
あんまり解説する気はなかったんだけど、いくらなんでも投げっぱなしかと思って書いてみた。
けどとても拙いので、なんとも言えない気分。

この辺りの混乱した箇所は今はもう大筋は理解できているので難しいとは思わないけど、こういう解説(?)が必要になる時点で難しいだろ、という事なのだろうか...
多分難しい難しくないではなくて、違うパラダイムだよ、ってだけの話なんじゃあないかな...
当然の様に継承とかは使うだろうけど、それだって最初は難しかったんじゃあないかなぁ

ちなみにこのパラダイム(?)に近いのは身近なところだと javascript とか jQuery とかだと思ってます。
あいつらコールバックに処理自体を渡したり、`{ }( )`とか`( )( )`とか良くやってるイメージなので似ていると思う。
もちろん haskell も。ぶっちゃけ haskell の関数は全てカリー化されているというところまで分かれば scala のここまでは一発で分かると思う。

勢いで始めたけど微妙なポエムになった。ちょい残念。