【解答例】Scala ラムダ 超入門

[Scala ラムダ 超入門](http://qiita.com/shigemk2/items/3a5e5df9fe85cf0b4eb2)の解答例です。

# 階乗

【問1】次に示す関数`fact`をラムダ式で書き換えてください。

```scala:factorial_lambda.scala
val fact : Int => Int = n => {
  n match {
    case 0 => 1
    case n if n > 0 => n * fact(n - 1)
  }
}

println(fact(5))
println(fact(0))
```

```text:実行結果
120
1
```

# 複数の引数

【問2】次に示す関数`add`をラムダ式で書き換えてください。

```scala:add_lambda.scala
val add : (Int, Int) => Int = (x, y) => x + y

println(add(2, 3))
println(add(9, 3))
```

```text:実行結果
5
12
```

# 無名関数

【問3】次に示す関数`add`を定義せずに、呼び出し側で無名関数にインライン展開してください。

```scala:lambda_function_add_inline.scala
println(((x: Int, y: Int) => x + y)(2, 3))
```

```text:実行結果
5
```

# 高階関数

## 引数

【問4】次に示す関数`f`と`add`を定義せずに、呼び出し側で無名関数にインライン展開してください。

```scala:higher_order_parameter_without_function.scala
println(((g: (Int, Int) => Int) => g(1, 2))((x: Int, y:Int) => x + y))
```

```text:実行結果
3
```

## 戻り値

【問5】次に示す関数`add`を定義せずに、呼び出し側で無名関数にインライン展開してください。

```scala:add_return_value_lambda.scala
println(((x: Int) => (y: Int) => x + y)(1)(2))
```

```text:実行結果
3
```

# カリー化

【問6】次に示す関数`combine`を、引数1つずつに分割してネストさせたラムダ式で書き換えてください。

```scala:combine_lambda.scala
val combine = (a: Any) => (b: Any) => (c: Any) => a +: b +: List(c)

val a = combine(1)
val b = a(2)
val c = b(3)
println(c)
println(combine('a')('b')('c'))
```

```text:実行結果
List(1, 2, 3)
List(a, b, c)
```

# 部分適用

【問7】次のコードから関数`double`を除去してください。ラムダ式は使わないでください。

```scala:double_partial_application.scala
def f(xs: List[Int], g: (Int) => Int) = for (x <- xs) yield g(x)

println(f(List(1,2,3,4,5), (2.*)))
```

```text:実行結果
List(2, 4, 6, 8, 10)
```

# 演算子

【問8】次のコードからラムダ式を排除してください。新しい関数を定義してはいけません。

```scala:operator_without_lambda.scala
def f1(g: (Int) => Int) = g(1)
def f2(g: (Int, Int) => Int) = g(2, 3)

// 新しい関数を定義してはいけない
// def sub1(x:Int) = x - 3
// def sub2(x:Int) = 3 - x
// def add(x:Int, y: Int) = x + y

println(f1(3-_))
println(f1(_-(3)))
println(f2(_+_))
```

```text:実行結果
2
-2
5
```

# 再実装

## 再帰

【問9】`map`, `filter`, `flip`, `foldl`, `foldr`を再帰で再実装してください。関数名には`m`を付けてください。

```scala:recursion.scala
def mmap(g: Int => Int, xs: Seq[Int]): Seq[Int] = {
  xs match {
    case m if m.isEmpty => Seq()
    case xs: Seq[Int] => g(xs.head) +: mmap(g, xs.tail)
  }
}

def mfilter(g: Int => Boolean, xs: Seq[Int]): Seq[Int] = {
  xs match {
    case xs if xs.isEmpty => Seq()
    case xs if g(xs.head) == true  => xs.head +: mfilter(g, xs.tail)
    case xs if g(xs.head) == false => mfilter(g, xs.tail)
  }
}

def mflip[A, B, C](f: (A, B) => C)(x: B)(y: A) = f(y, x)

def mfoldLeft(g: (Int, Int) => Int, z: Int, xs: Seq[Int]): Int = {
  (g, z, xs) match {
    case (g, z, xs) if xs.isEmpty => z
    case (g, z, xs) => mfoldLeft(g, g(z, xs.head), xs.tail)
  }
}

def mfoldRight(g: (Int, Int) => Int, z: Int, xs: Seq[Int]): Int = {
  (g, z, xs) match {
    case (g, z, xs) if xs.isEmpty => z
    case (g, z, xs) => g(xs.head, mfoldRight(g, z, xs.tail))
  }
}

println(mmap((_*2), (1 to 5)))
println(mfilter((x => x < 5), (1 to 9)))
println(mflip(mmap)(1 to 5)(_*2))
println(mfoldLeft((_+_), 0, (1 to 100)))
println(mfoldLeft((_-_), 0, (1 to 5)))
println(mfoldRight((_-_), 0, (1 to 5)))
```

```text:実行結果
List(2, 4, 6, 8, 10)
List(1, 2, 3, 4)
List(2, 4, 6, 8, 10)
5050
-15
3
```

## foldLeft

【問10】`foldLeft`で`reverse`と`maximum`と`minimum`を再実装してください。関数名には`m`を付けてください。

```scala:foldleft_reverse_max_min.scala
def mreverse(xs: Seq[Int]): Seq[Int] = {
  xs.foldLeft(Seq[Int]())((z, n) => n +: z)
}

def maximum(xs: Seq[Int]): Int = {
  xs.foldLeft(xs.head)((z, n) => if (z < n) n else z)
}

def minimum(xs: Seq[Int]): Int = {
  xs.foldLeft(xs.head)((z, n) => if (z > n) n else z)
}

println(mreverse((-5 to 5)))
println(maximum((-5 to 5)))
println(minimum((-5 to 5)))
```

```text:実行結果
List(5, 4, 3, 2, 1, 0, -1, -2, -3, -4, -5)
5
-5
```

# クイックソート

【問11】次に示す関数`qsort`を`filter`で書き替えてください。引数にはList型のリストを使用してください。

```scala:qsort_filter.scala
def qsort(xs: List[Int]): List[Int] = {
  if (xs.length <= 1) xs
  else {
    val pivot = xs(xs.length / 2)
    qsort(xs.filter(pivot >)) ++
    xs.filter(pivot ==) ++
    qsort(xs.filter(pivot <))
  }
}

println(qsort(List(4, 6, 9, 8, 3, 5, 1, 7, 2)))
```

```text:実行結果
List(1, 2, 3, 4, 5, 6, 7, 8, 9)
```

# バブル

【問12】次に示すバブルソートの関数`bswap`を`foldRight`で書き替えてください。

```scala:bsort_foldright.scala
def bsort(list: List[Int]): List[Int] = {
  def bswap(xs: List[Int]): List[Int] = {
    xs.foldRight(List[Int]())((z, n) => {
      n match {
        case n if n.isEmpty => List(z)
        case n => {
          if (z > n.head) n.head :: z :: n.tail
          else z :: n.head :: n.tail
        }
      }
    })
  }
  val ys = bswap(list)
  ys match {
    case list if ys.isEmpty => List()
    case list => ys.head :: bsort(ys.tail)
  }
}

println(bsort(List(4,3,1,5,2)))
println(bsort(List(4,6,9,8,3,5,1,7,2)))
```

```text:実行結果
List(1, 2, 3, 4, 5)
List(1, 2, 3, 4, 5, 6, 7, 8, 9)
```

# sum

【問13】Yコンビネータを使って関数`sum`を再実装してください。

```scala:sum_y.scala
def Y[A,B]( f:((A => B), A ) => B, x:A ):B = f( ( y:A ) => Y( f,y ),x )

val y = Y( (f:Seq[Int] => Int , n:Seq[Int]) => n match {
  case n if n.isEmpty => 0
  case _ => n.head + f(n.tail)
}, (1 to 100))

println(y)
```

```text:実行結果
5050
```