Sassyブログ

好きなことで暮らしを豊かにするブログ

関数型プログラミングについて

目次

関数型プログラミングは言葉だけは知っており、CやJavaみたいな手続き型プログラミングとは異なり宣言型プログラミングであるという程度の知識しかない。
じゃあ具体的に宣言型プログラミングってなんだ?ってところの話も含めて調べていってみようと思う。

1.関数型プログラミングとは?

複数の関数同士を組み合わせてプログラミングしていく手法。
手続き型プログラミングと比べて、全体を1つの式としてまとめて記述するそう。

まず手続き型プログラミングで1から10までの整数を足していくプログラムを書くと以下のように状態変数を使用して、
その状態変数に数値を足す処理をループで繰り返し行うことで処理していきます。

以下サンプルコードについては、Wikipediaのものを参考にさせていただき筆者がJavaで書き直しました。

関数型プログラミング - Wikipedia

Java8であれば関数型インターフェースがあるのでそちらを使用したほうがもっとらしくかけるのかな?
あくまでここでは手続き型ではループで処理で状態変数を使用しているのに対し、関数型では再帰処理で状態変数を使わずに処理をしているよということを伝えたいので細かい部分は気にしないでください。

1-1.手続き型の場合

public class Sample {

  public static void main(String arg[]) {
    System.out.println(sum(10));
  }
  public static int sum(int a){
    int total = 0;
    for(i = 0, i <= a, i++) {
      total = total + i;
    }
    return total;
  }
}

1-2.関数型の場合

public class Sample {

  public static void main(String arg[]) {
    System.out.println(sum(10));
  }

  public static int sum(int a){
    if(a == 0) {
      return 0 ;
    } else {
      return a + sum(a - 1);
    }
  }
}

2.宣言型プログラミングって?

関数型を調査していくうちに宣言型プログラミングと言うワードが出てきました。
宣言型プログラミングってなんだよ?って感じですよね。。

手続き型プログラミングではある出力を得るための操作を上から順番に記述していきます。

しかし、宣言型プログラミングではそのような問題の解法を記述してはいかず、問題の性質を記述していきます。

3.関数型プログラミングのメリットとデメリットについて

3-1.メリット

  • 代入文を含まない。
  • 一度与えられた変数は変更されないため、プログラムの副作用が無い。
  • プログラマは問題への手順を記述しなくてもよくなる。

3-2.デメリット

  • 大多数のプログラマが手続き型の方の経験が多いため学習コストが掛かる。
  • 数学的な考え方が必要になる。

4.関数型プログラミングを学ぶには?

言語はScalaになりますが、筆者のオススメとしてはまずドワンゴさんがgithubで公開している入門を実施してみると良いと思います。

https://dwango.github.io/scala_text/

その次に以下の参考書をベースに課題を実施しながら読み進めていくとだいたいscala含め関数型の感覚が身につくかと思います。

【書籍】Scala関数型デザイン&プログラミング―Scalazコントリビューターによる関数型徹底ガイド

そして、細かいところは下記の参考書で補う感じで

5.さぁ始めよう関数型プログラミング

4章の内容を学習すれば関数型が身についてきますので、 そしたら次は下記のサイトのハンズオンを実践して実際に関数型でWebアプリケーションを構築していく方法を身に着けていくと良いと思います。

http://bizreach.github.io/play2-hands-on/

6.関数型プログラミングメモ

筆者のメモです。

参照透過性

プログラムの意味を変えることなく、式をその結果に置き換えることができる。と記載されています。 これがどういうことかというと2 + 3という式の結果が5となり、この2 + 3の部分を5に置き換えてもプログラムの意味は変わらないということになります。 参照透過は純粋関数であるといえます。

わかりやすくコードで説明すると

def factorial(n: Int): BigInt = {
  if(n == 0)
    1
  else
    n * fact(n - 1)
}

上記の関数の引数に5を与えた場合、関数内のプログラムは下記のように置き換えたものと意味は変わらない。

def factorial(): BigInt = {
  5 * (4 * (3 * (2 * (1 * 1))))
}

つまり上記の関数は参照透過であるといえる。

高階関数

関数の引数に他の関数を渡している関数のこと。 高階関数のパラメータ名として「f」「g」「h」のような名前を付けるのが慣例となっているそうです。 関数型プログラミングでは頻繁に短い変数名が出現することがあるそうです。 この省略された変数名には汎用的な意味があるそうで、この変数に入る値の実際の目的が説明できないからです。

高階関数のサンプルコードは以下になります。 ※言語はscalaです。

def sample(n: Int, f: Int => Int) = {
  val test = " %d => %d"
  msg.format(n, f(n))
}

単相関数

1つの型のデータだけを操作する関数のこと。
通常の関数定義だとこの単相関数になる。

多相関数

様々な型のデータを操作することができる関数のこと。
Javaで言ったらジェネリック的なやつ。

カリー化

2引数以上の関数を、1引数の関数の定義だけで同じ機能を持つように定義を書き換えること。

Option

これは関数型というよりはScalaにある機能ですね。。。
とりあえずメモとして載せておきます。

ある入力に対して、出力結果が常にあるとは限らない場合に戻り値を型で表すことができる。
エラーが発生したかどうかだけで十分な場合には、Optionを使用したほうが単純であるため有効。

Either

これは関数型というよりはScalaにある機能ですね。。。
とりあえずメモとして載せておきます。

例外に関する情報を教えてくれる。
エラーをの原因を突き止める場合に有効。

以上