関数型言語、聞いたことあるけど結局何なの?

概要

エニグモ サーバーサイドエンジニアの @gugu です。 この記事はEnigmo Advent Calendar 2018の24日目です。

関数型言語って結局何なの?と思ったので調べてみました。私が疑問に思ったことをベースに調べた内容を記載していこうと思います。

関数型言語として主にHaskellをメインに調べているので、関数型言語すべての話ではない記述があるかもしれません。

対象者

参考書

参考サイト

ありがとうございます!

関数型言語の疑問

「関数型」っていうけど手続き型でもオブジェクト指向でも関数を書くじゃん?

私がはじめに思った疑問です。みなさんもそう思いませんか? 下記のようです。

  • 関数型言語の関数というのは副作用のない純粋な関数のこと。(詳しくは後述)
  • すべてが関数でできている。Haskellだとif文も関数なのでelseの省略は不可。※言語によってそれぞれ例外あり。(そもそも何か値を返すのが「関数」、返さないのが「プロシージャ」と呼ぶ。C言語からプロシージャも含めて「関数」と呼ぶようになったとか。)
  • オブジェクト指向ではクラス内に関数を書く。(お作法的に。なぜこんな話をするのかは後述)

関数型言語の中でもマルチパラダイム言語って両方使えて最強じゃね?

結論から言うとそうでもないらしいです。

その前に関数型言語の種類について説明。。。

オブジェクト指向が備わっているということは副作用が発生する可能性が増えるということ、つまり関数型言語の本来の目的とズレてしまっていることになります。(もちろん適材適所でオブジェクト指向と関数型で使い分けられるメリットはあるかと。)

別に関数型言語でなくてもオブジェクト指向で副作用なく作れば良いのでは?

まずは先に副作用がないとはどういうことか

雑な説明かもしれませんが、変数が途中で変わらず参照透明であることです。

束縛

関数型言語で変数に「代入」することを「束縛」と呼びます。代入と違う点は一度値を入れると変更できません。

x = 1
x = 2 -- error

参照透過性

引数が同じなら返り値も必ず同じになる関数のことを「参照透過性」と言います。

で、オブジェクト指向でも参照透明に書けば良いのでは?

その通りで、オブジェクト指向でも副作用を避けて書くことは大事です。ですが、そもそも言語としてのアプローチが異なります。

関数型言語は副作用が起きづらい?だから?

下記メリットがあります。

  • テストや保守を容易にする
  • バグがおこりずらい
  • 再利用可能な部品を作りやすい
  • (注目)遅延評価

遅延評価

副作用がないので実現可能に。 使用するときに一度だけ計算されキャッシュされます。無駄な処理を省くことができます。

関数型言語ってどうやって書くの?

これが代表例なのかわかりませんが、私が一番なるほどと思ったのはループ文です。 関数型言語は関数がメインなのでループをさせる際はfor文ではなく再帰を使用します。(Haskellだとそもそもforもwhileも無いみたいです。)

Wikipedia(関数型言語)

で、オブジェクト指向関数型言語どちらで書くべき?

すみません、わからないです。。。(汗) 個人的な意見だと、やはり堅牢でテストコードの書きやすい関数型言語がベターなような気がしますが、オブジェクト指向のほうが「オブジェクト」を自然と意識して作れるので設計しやすいような気もします。ただ書き慣れているだけかもしれないのでやはり関数型言語なのでしょうか。

関数型言語の勉強にScalaは向いていないかも。。

関数型言語の勉強でScalaを勉強していたのですが、結局はオブジェクト指向脳を使ってオブジェクト指向で書いてしまうので、なにが関数型言語の特徴なのか理解しづらいです。関数型言語を学びたければ純粋型を学ぶのが良いかと思います。

まとめ

実際私が関数型言語への疑問を中心に書いたので、偏った知識かもしれません。しかし同じような疑問を持っている方に少しでも役にたてばと思って書いてみました。

調べた感じだと関数型言語は良いことづくしなような気もしますが、数学的でやはりとっつきにくいイメージも大きいかと思いました。結局は「関数型言語を知りたければ関数型言語で書くべし!」なんでしょうね。。関数型言語と仲良くなれるようにがんばります!