初学者がScalaで不思議だったこと集

# 前提
- Javaの学習を一通り終えた投稿者が、Javaと相互運用性のある関数型プログラミング言語 Scala について印象を述べる記事
- 感想等ありましたら、お気軽にコメントください

# 概要
- オブジェクト指向言語兼、本格的な関数型言語

# なぜScalaなのか
### 互換性
- JVM上で動くため、Javaと互換運用性がある
### 簡潔性
- Javaでかく場合の半分以下のコード量になる
```MyClass.java
class MyClass {
 private int age;
 private String name;
 public MyClass(int age, String name) {
     this.age = age;
     this.name = name;
 }
}
```

以下と同じ
```MyClass.scala
class MyClass(var age: Int, var name: String) {}
```
- 上記だけ見ると省略できすぎて
    - ちょっと魔法っぽい

# String型
- Javaのjava.lang.String型が使われている

# 定数、変数
- 型推論機能がある
```scala
val hoge = "huga" // 代入不可
var hoge = "huga" // 代入可
```

# 関数
- パラメータ、戻り値の型を指定する
```scala
  def max(x: Int, y: Int): Int = {
    if (x > y) x else y
  }

  def max(x: Int, y: Int): Int = if (x > y) x else y // 1行で済むなら中括弧を省略できる
```

# リスト連結
- Listオブジェクトはリストを連結できる`:::`というメソッドを持っている
- また、`::`で、リスト先頭に要素を追加できる
```scala
val oneTwo = List(1, 2)
val threeFour = List(3, 4)
val oneTwoThreeFour = oneTwo ::: threeFour
val zeroOneTwoThreeFour = 0 :: oneTwoThreeFour
```

# タプル
- 便利なコンテナオブジェクトで、`List[String], List[Int]`のように制限なく文字列や数値を配列要素として挿入できる

# trait
- javaでいうインターフェースのようなもの
- クラス、オブジェクトはtraitを継承できるが、traitはインスタンス化ができない
```scala
trait Iterator[A] {
  def hasNext: Boolean
  def next(): A
}
```
## 継承 extends
- traitのメソッドにアクセスできる
```scala
class IntIterator(to: Int) extends Iterator[Int] {
```
### 実装 override
ー traitで抽象化されたメソッドを実装する
```scala
trait Iterator[A] {
  def hasNext: Boolean
  def next(): A
}

class IntIterator(to: Int) extends Iterator[Int] {
  private var current = 0
  override def hasNext: Boolean = current < to
  override def next(): Int =  {
    if (hasNext) {
      val t = current
      current += 1
      t
    } else 0
  }
}


val iterator = new IntIterator(10)
iterator.next()  // returns 0
iterator.next()  // returns 1
```
#### 余談
- Javaでは継承と実装を同時にやる際、クラス定義時にextendsとinclementsを書かなければいけなかったが、
    - scalaでは定義時、extendsするだけで良いのかな？

# mixin
- 継承せずに継承したかのように振る舞い、メソッド等を使える
- クラスは一つしかスーパークラスを持つ事ができないが、ミックスインは複数持てる
- ミックスインされるクラスはtraitで作成する

```scala
abstract class A {
  val message: String
}
class B extends A {
  val message = "I'm an instance of class B"
}
trait C extends A {
  def loudMessage = message.toUpperCase()
}
class D extends B with C

val d = new D
println(d.message)  // I'm an instance of class B
println(d.loudMessage)  // I'M AN INSTANCE OF CLASS B
```
## なぜミックスインなのか
- Javaでは菱形継承問題という多重継承の課題があった
- それを改善するためにこの仕様を考えたのかもしれない。（違ってたらコメントください）

# メソッドをネストする
```scala
 def factorial(x: Int): Int = {
    def fact(x: Int, accumulator: Int): Int = {
      if (x <= 1) accumulator
      else fact(x - 1, x * accumulator)
    }  
    fact(x, 1)
 }

 println("Factorial of 2: " + factorial(2)) // 2
 println("Factorial of 3: " + factorial(3)) // 6
```

# カリー化
- **複数の引数を受け取る関数**を
    - **１つの引数を受け取り、残りの引数を受け取る関数を返す関数**に変換すること
        - ちょっとややこしすぎない？
```scala
val add = {(x:Int, y:Int, z:Int) => x + y + z}
val addCurried = add.curried
val addCurriedWithX = addCurried(1)
val addCurriedWithXY = addCurriedWithX(2)
println(addCurriedWithXY(3)) //この時点で6が返される
```
- ~~ステフィンカリーがどうしても頭によぎる~~
    - ~~カリーになれるならなりたいっす~~

# ケースクラス
- 不変なデータを作るのに適しているクラス
- インスタンス化するときにnewを使わない
    - ケースクラスがオブジェクトの生成を行うapplyメソッドを標準で保有するため

```scala
case class Message(sender: String, recipient: String, body: String)
val message1 = Message("guillaume@quebec.ca", "jorge@catalonia.es", "Ça va ?")

println(message1.sender)  // guillaume@quebec.ca が出力されます
message1.sender = "travis@washington.us"  // この行はコンパイルされません
```
### 参照ではなく、構造で比較される
- 引数に入れた値が一緒ならインスタンスのアドレスが異なっても等値扱い
    - ==は等値でequals()は等価だとJavaで習った
```scala
case class Message(sender: String, recipient: String, body: String)

val message2 = Message("jorge@catalonia.es", "guillaume@quebec.ca", "Com va?")
val message3 = Message("jorge@catalonia.es", "guillaume@quebec.ca", "Com va?")
val messagesAreTheSame = message2 == message3  // true
```

### コピー
- copyメソッドを使うことで簡単にケースクラスのインスタンスの（浅い）コピーを作ることができる
    - 必要に応じて、コンストラクタ引数を変更することもできる
```scala
case class Message(sender: String, recipient: String, body: String)
val message4 = Message("julien@bretagne.fr", "travis@washington.us", "Me zo o komz gant ma amezeg")
val message5 = message4.copy(sender = message4.recipient, recipient = "claire@bourgogne.fr")
message5.sender  // travis@washington.us
message5.recipient // claire@bourgogne.fr
message5.body  // "Me zo o komz gant ma amezeg"
```

# マッチング
## パターンガード
- パターンの後ろにif文をつける
```scala
def showImportantNotification(notification: Notification, importantPeopleInfo: Seq[String]): String = {
  notification match {
    case Email(sender, _, _) if importantPeopleInfo.contains(sender) =>
      "You got an email from special someone!"
    case SMS(number, _) if importantPeopleInfo.contains(number) =>
      "You got an SMS from special someone!"
    case other =>
      showNotification(other) // 特別なものではなく、オリジナルのshowNotification関数に委譲します。
  }
}

val importantPeopleInfo = Seq("867-5309", "jenny@gmail.com")

val someSms = SMS("867-5309", "Are you there?")
val someVoiceRecording = VoiceRecording("Tom", "voicerecording.org/id/123")
val importantEmail = Email("jenny@gmail.com", "Drinks tonight?", "I'm free after 5!")
val importantSms = SMS("867-5309", "I'm here! Where are you?")

println(showImportantNotification(someSms, importantPeopleInfo))
println(showImportantNotification(someVoiceRecording, importantPeopleInfo))
println(showImportantNotification(importantEmail, importantPeopleInfo))
println(showImportantNotification(importantSms, importantPeopleInfo))
```
- これ他の言語でもあった？
## 型のみのマッチング
- 以下のように型のみでマッチングする事ができる
```scala
abstract class Device
case class Phone(model: String) extends Device {
  def screenOff = "Turning screen off"
}
case class Computer(model: String) extends Device {
  def screenSaverOn = "Turning screen saver on..."
}

def goIdle(device: Device) = device match {
  case p: Phone => p.screenOff
  case c: Computer => c.screenSaverOn
}
```

## シールドクラス
- traitまたはクラスにsealdをつけると、
    - 全てのサブタイプは同一ファイル内で宣言されなければならなくなる。

```scala
sealed abstract class Furniture
case class Couch() extends Furniture
case class Chair() extends Furniture

def findPlaceToSit(piece: Furniture): String = piece match {
  case a: Couch => "Lie on the couch"
  case b: Chair => "Sit on the chair"
}
```

# シングルトンオブジェクト
- 一つのクラスから一つのインスタンスしか作れない。

```scala
package logging

object Logger {
  def info(message: String): Unit = println(s"INFO: $message")
}
```
上記で作ったinfoは、下記のように使われる
```scala
import logging.Logger.info //メソッド名まで記述して、呼び出せるようにする

class Project(name: String, daysToComplete: Int)

class Test {
  val project1 = new Project("TPS Reports", 1)
  val project2 = new Project("Website redesign", 5)
  info("Created projects")  // Prints "INFO: Created projects"
}
```

## コンパニオンオブジェクト
- クラスと同じ名前のオブジェクト
- 逆にそのクラスはオブジェクトのコンパニオンクラスと呼ばれる
- コンパニオンオブジェクト、コンパニオンクラスは自信のコンパニオンのプライベートメンバーにアクセスできる。
```scala
import scala.math._

case class Circle(radius: Double) {
  import Circle._
  def area: Double = calculateArea(radius)
}

object Circle {
  private def calculateArea(radius: Double): Double = Pi * pow(radius, 2.0)
}

val circle1 = Circle(5.0)

circle1.area
```
- コンパニオンオブジェクトはファクトリーメソッドを含むことができる
    -                                                 
```scala
class Email(val username: String, val domainName: String)

object Email {
  def fromString(emailString: String): Option[Email] = {
    emailString.split('@') match {
      case Array(a, b) => Some(new Email(a, b))
      case _ => None
    }
  }
}

val scalaCenterEmail = Email.fromString("scala.center@epfl.ch")
scalaCenterEmail match {
  case Some(email) => println(
    s"""Registered an email
       |Username: ${email.username}
       |Domain name: ${email.domainName}
     """.stripMargin)
  case None => println("Error: could not parse email")
}
```
 
# 抽出子
- unapplyメソッドが定義されているオブジェクトのこと
    - 受け取ったインスタンスを分解して、 何かを抽出する役割がある

- パターンマッチングと部分関数で頻繁に使われる

```User.scala
 class User(private val firstname: String, private val lastname: String)

 object User {
   def unapply(user: User) = Option((user.firstname, user.lastname))
 }
```
上記のUserコンパニオンオブジェクトの抽出子で、Userインスタンスを受け取り、苗字と名前に分解している

```Main.scala
  object Main extends App {
    val user = new User("剛次", "赤石")

    user match {
      case User(firstname, lastname) => println(lastname + " " + firstname)
      case _ => println("Not user.")
    }
  }
```

- 上記のMainオブジェクトのマッチングで`User(firstname, lastname)`というcase指定があるが、これはunapplyメソッドを呼び出している？らしい
    - ちょっと難解では

# for内包表記
- シンプルにリストを操作するための書き方
- `for (enumerators) yield e`という形をとる
- yieldをつけると`List[String]`型を返し、つけないと`Unit`型を返す
- 
```scala
case class User(name: String, age: Int)

val UserBase = List(User("taro", 40),
 User("joro", 28),
 User("Saburo", 18),
 User("kyoko", 25)) 

val twentySomethings = for (user <- UserBase if (user.age >= 20 && user.age <= 30))
 yield user.name

twentySomethings.foreach(name => println(name))
```

# 可変長引数と再帰データ型
- 型の後に*をつけることによって、適当な個数の引数を任意にとれる

```scala
case class Person(name: String, age: Int, child: Person*)

val child1 = Person("Child1", 5)
val child2 = Person("Child2", 3)
val parent = Person("Parent", 30, child1, child2)
```

# 変位指定
- クラスの型パラメータがどのように継承されるかを決める仕組み
- クラスの再利用性を高め、型システムをより強力にするための重要な機能
## 共変
### 前談
- ぱっと見、以下の仕様と似ていると思った
    - Javaの変数宣言の型で、親のクラス型を指定しても良い
        - インスタンス化は子クラス
```java
public class Human {
    ...
}
public class Man extends Human {
    ...
}

Human ron = new Man();
```
ManはHumanだよね(is-aの原則)ってことでコンパイルエラーにならない
### 本題
- List[A]がList[B]のサブタイプというようなことを利用して、仮引数にList[A]を指定しても、実引数でサブタイプ元のList[B]を指定できる、という仕様
    - 合ってる自信ない（間違ってたらご指摘ください）
```scala
abstract class Animal {
  def name: String
}
case class Cat(name: String) extends Animal
case class Dog(name: String) extends Animal

object CovarianceTest extends App {
  def printAnimalNames(animals: List[Animal]): Unit = {
    animals.foreach { animal =>
      println(animal.name)
    }
  }

  val cats: List[Cat] = List(Cat("Whiskers"), Cat("Tom"))
  val dogs: List[Dog] = List(Dog("Fido"), Dog("Rex"))

  printAnimalNames(cats) // 実引数でサブタイプ元のAnimalを指定してるが、仮引数でCatを指定
  // Whiskers
  // Tom

  printAnimalNames(dogs) // 実引数でサブタイプ元のAnimalを指定してるが、仮引数でDogを指定
  // Fido
  // Rex
}
```
## 反変
- 共変とちょうど対になる性質
- 型パラメータを持ったクラスG、型パラメータAとBがあったとき、A が B を継承しているときにのみ、

```scala
val : G[A] = G[B]
```
が成り立つ

# 内部クラス
- クラスの中にクラスを定義できる

# Unit型
- 値が無いことを表す型で、値をただ一つのみ持つ
- 値として意味がないことを示す

```scala
def printInt(x:int): Unit = println(x)
```

# 遅延評価
- 大雑把に言うと、必要になるまで計算を遅らせる機能
- 通常は、変数や関数の結果は宣言されたときにすぐに計算されるが、遅延評価では実際に値が必要になるまで計算を行わない
- 使いたい場合は、lazyキーワードを使う
```scala
lazy val lazyValue = {
  println("計算しています...")
  42
}

println("まだ計算していません")
println(lazyValue) // この時点で初めて計算が行われる
println(lazyValue) // 既に計算済みなので再度計算しない
```

- 遅延評価は、キャッシュされるため一度計算した結果は再評価されない
    - 望ましくない場合は、再計算が必要な状況に応じて工夫する必要がある

# まとめ
- 抽出子と変位指定がわかりづらかったので間違っている場合はご指摘ください。