post Image
第2章:What is 関数型言語?

Scalaの醍醐味は関数型言語とオブジェクト指向言語のハイブリッドだ!

今回はオブジェクト指向をやっている人には馴染みが薄い、
関数型言語について語るよ。

関数型言語って何?

関数を駆使してプログラミングできる言語が、関数型言語だ!
関数とはオブジェクト指向でいうと「メソッド」みたいなもんだ。
意味は違うけどね。数学的な例だと、

y = sin(x)

これは引数xを与えると、sinが計算して値をyに代入するんだ。
ここではsin(x)が関数だよ。

次にScalaで関数を作ってみるよ。

FunctionExample.scala
object FunctionExample{
  def main(args: Array[String]){

    var calculate = (x: Int) => x + 5 : Int

    printf("y=%s \n", calculate(1))
    printf("y=%s \n", calculate(2))
  }
}

実行すると以下のようになるよ。

$ scala FunctionExample.scala
y=6
y=7

FunctionExample.scalaで定義した関数は、calculate
引数に数値を与えると、その引数に5を足して返す関数だ。
これは、y=x+5という一次関数を表してるんだよ。

誤解を恐れずに言うと、Cの関数やJavaのメソッド
と同様に処理を表す部分でもある。
もちろん違いはあるので、関数型言語の特徴と言う形で述べていこう。

関数型言語の特徴

  • immutable (いみゅーたぶる)
  • 副作用がない
  • 関数はファーストクラス(第一級)

関数型言語の特徴を調べると、上記のような項目が必ず出てくる。
最初はよくわからないよね?
でも基本だから避けては通れないよ。

immutable(いみゅーたぶる)

immutableとはim(in) + mutableのことだ。
mutable?「変わる」ことだよ。immutable「変わらない」ことだね。
「変わる」って何が?変わるのは値だよ。

Scalaでこれを端的に表すキーワードが存在している。
varvalだ。

Mutable.scala
object Mutable{
  def main(args: Array[String]){
    var mutable = "Mutable"
    printf("%s ", mutable)

    mutable = "Change mutable"
    printf("%s ", mutable)
  }
}

実行すると、varで定義した変数mutableの値が切り替わることがわかるね。
これがmutableだ。

$ scala Mutable.scala
Mutable
Change mutable

次にimmutable。

Immutable.scala
object Immutable{
  def main(args: Array[String]){
    val immutable = "Immutable"
    printf("%s ", immutable)

    immutable = "Change immutable"
    printf("%s ", immutable)
  }
}

実行するとコンパイルエラーが発生する。

$ scala Immutable.scala
Immutable.scala:6: error: reassignment to val
immutable = "Change immutable"
          ^
one error found

immutable、即ちvalで定義した変数の値が変えられないことがわかったかな?

副作用がない

本来するべきことを作用とすれば、作用に伴って別のことをしてしまうのが副作用だ。

風邪をひいたらどうする?
風邪薬を飲むよね。飲んだら眠くなることない?
風邪薬では、風邪を治すことが作用、眠くなることが副作用だ。

副作用の具体例をソースで表してみるよ。

SideEffect.scala
object SideEffect{
  var total = 0

  def main(args: Array[String]){
    var add = (x:Int) => {
      total+=x
      total
    }

    printf("total=%s \n", add(1))
    printf("total=%s \n", add(1))
    printf("total=%s \n", add(1))
  }
}

実行すると以下のようになる。

$ scala SideEffect.scala
total=1
total=2
total=3

この例では、メソッドaddを引数1で3回呼んでいるが、
呼ばれるたびにtotalを足している。

そのため、addは呼ばれるたびに異なる戻り値を返す。
addはオブジェクトフィールドtotalにも作用していることを、
副作用と言う。

副作用のない例は以下となる。

NoneSideEffect.scala
object NoneSideEffect{
  def main(args: Array[String]){
    var add = (x: Int) => x + 5

    printf("add=%s \n", add(1))
    printf("add=%s \n", add(1))
    printf("add=%s \n", add(1))
  }
}
$ scala NoneSideEffect.scala
add=6
add=6
add=6

SideEffect.scalaはオブジェクト指向ぽく書いたけど、
まさしくオブジェクト指向は副作用の塊だね。

もちろん関数型言語を駆使すれば、副作用を全て排除できるわけではないよ。
IOに関わる部分は副作用だからね。
でもなくせる場所では副作用をなくそうぜ!

関数はファーストクラス(第一級)

ファーストクラス(第一級)とは、関数を型として扱えるってことなんだ。
文字列型とか数値型とかと同じにみなせる。
型として扱えるということは、var addみたいな変数に、関数を設定することが可能なんだよ。
JavaScriptのvar func = function(){......};と同じだね。

次にファーストクラスの利点。
– 関数の引数として渡せる
– 関数の戻り値として返せる

Javaにはできないことだよ。メソッドだけをオブジェクトとして返せないからね。
メソッドはオブジェクトありきなんだ。

関数の戻り値の例で見てみよう。

FirstClassFunction.scala
object FirstClassFunction{
  def main(args: Array[String]){
    val add = (x: Int) => {
      val _add = (y: Int) =>  y + 5
      _add(x)
    }

    printf("add=%s \n", add(1))
    printf("add=%s \n", add(2))
    printf("add=%s \n", add(1))
  }
}

実行してみよう!

$ scala SideEffect.scala
add=6
add=7
add=6

関数addの戻り値はなんと関数_addだ!
変数funcには、add()の戻り値_addが入っている。
そしてfunc(1)_add(1)を評価することと同じになる。
だからfunc(1)の結果は6になるのさ。

ちなみにファーストクラスのクラスは、オブジェクト指向のクラスとは
全く関係ないから注意してね!

最上級だ!!!

言語の翻訳ではよく「functions as first-class citizens」って言葉が出てきて
「第一級市民である関数」なんて訳されているよ。

関数とメソッドの違い

Java等のオブジェクト指向言語を使っていると、関数とメソッドの違いがわからないかもしれない。

メソッドはあくまでオブジェクトと関連付いているんだ。
オブジェクトの操作をメソッドと言う。

オブジェクトには状態(フィールド)があるんだけど、
状態によって戻り値が変わる。引数がなくても、
戻り値が変わることがあるんだ。

staticおじさんの作りしかしらなかったら、ゴメンナサイ!

一方関数は、引数に依存する。
引数が同じなら常に同じ戻り値を返し、
引数が変わったら別の戻り値を返す。
状態には依存させないよ。

文法上の違いもあるよ。

defキーワードはメソッドになる。

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

これは関数リテラルで、関数となる。

var add = (x:Int, y:Int) => x + y

まとめ

今回は関数型言語について語ってみたけど難しかったかな?

実は僕も、関数型言語を理解するために日々悩んでいるんだ。
それだけ難しい概念だと思うけど、
ここを掌握できればプログラミングの質が上がると信じているよ。

今回の、関数型言語のソースを実際に動かすことで、

体で感じてくれたかな?


『 Scala 』Article List
Category List

Eye Catch Image
Read More

Androidに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Bitcoinに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Goに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

JavaScriptに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Pythonに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Rubyに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Scalaに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Swiftに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Unityに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Wordpressに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

機械学習に関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。