関数型プログラミング vs命令型プログラミング~Java8でフィボナッチ、素数、階乗をやってみた~

  • このエントリーをはてなブックマークに追加

      2016/05/18

関数型プログラミング vs命令型プログラミング~Java8でフィボナッチ、素数、階乗をやってみた~

プログラミングには多様な形式やパラダイムがあるが、有名なものを2つ挙げるとしたら、関数型命令型だろう。

命令型プログラミングは、ほとんど全ての主流言語(C++、Java、C#)が推し進めてきたこともあり、最も支配的パラダイムだ。しかし、ここ数年で関数型プログラミングが注目を集め始めている。その主な理由の一つは、単純に全ての新しいコンピュータが4、8、16コアを標準装備しており、命令型プログラミング形式では、全てのコアを活用して並列プログラムを書くことが非常に難しくなったことだ。関数型形式はこの困難な状況をランタイムに委ね、辛くてミスが起きやすい仕事から開発者を解放してくれる。

ちょっと待った!では、この2つの形式の違いは何なのだろうか?

命令型プログラミングとは、望む結果を得るために、マシンまたはランタイムがいかに正確に、どの正確な命令文を実行すべきかを命じるというパラダイムである。

関数型プログラミング とは、何を得たいかを伝え、マシンまたはランタイムがそのための最良の方法を決定するという、宣言型プログラミングのパラダイムの一種である。

関数型形式は方法の部分をランタイムに委ね、開発者が結果の部分に集中できるようにしてくれる。方法の部分を抽象化することで、より保守しやすくスケーラブルなソフトウェアを書くことができる。

マルチコアマシンの課題に対処し、開発者を依然として惹きつけ続けるために、Java8は命令型パラダイムの次に関数型パラダイムを導入した。

理屈はここまでにして、違いを見るためにJavaを使い、何個かのプログラミング課題を、命令型と関数型形式でそれぞれやってみよう。

フィボナッチ数列:命令型vs関数型

(フィボナッチ数列は、1, 1, 2, 3, 5, 8, 13, 21, 34, …といった一連の数字だ。次の数字は、前の2つの数字を足していくことで求められる)

反復および命令型形式でのフィボナッチ数列

public static int fibonacci(int number) {
  int fib1 = 1;
  int fib2 = 1;
  int fibonacci = fib1;
  for (int i = 2; i < number; i++) {
    fibonacci = fib1 + fib2;
    fib1 = fib2;
    fib2 = fibonacci;
  }
  return fibonacci;
}

for(int i = 1; i  <= 10; i++) {
  System.out.print(fibonacci(i) +" ");
}
// Output: 1 1 2 3 5 8 13 21 34 55

ご覧のとおり、をしたいか(結果)よりも、方法(反復、状態)により焦点を当てている。

反復および関数型形式でのフィボナッチ数列

IntStream fibonacciStream = Stream.iterate(
    new int[]{1, 1},
    fib -> new int[] {fib[1], fib[0] + fib[1]}
  ).mapToInt(fib -> fib[0]);

fibonacciStream.limit(10).forEach(fib ->
    System.out.print(fib + " "));
// Output: 1 1 2 3 5 8 13 21 34 55

それに対し、こちらではをしたいか(結果)に焦点を当てていることがわかる。

素数:命令型vs関数型

(素数は、正の約数が1または自分自身であり、1より大きい自然数)

命令型形式での素数

public boolean isPrime(long number) {
  for(long i = 2; i <= Math.sqrt(number); i++) {
    if(number % i == 0) return false;
  }
  return number > 1;
}
isPrime(9220000000000000039L) // Output: true

ここでもまた、方法(反復、状態)に焦点を当てている。

関数型形式での素数

public boolean isPrime(long number) {
  return number > 1 &&
    LongStream
     .rangeClosed(2, (long) Math.sqrt(number))
     .noneMatch(index -> number % index == 0);
}
isPrime(9220000000000000039L) // Output: true

さて、ここでもをしたいか(結果)に焦点を当てている。関数型形式は、数値の範囲を明示的に反復処理するプロセスを抽象化する手助けをしてくれた。

今あなたは、うーん、これだけ…?と思っているかもしれない。では、関数型形式でどのように全部のコア(並行処理を使う)を使うことができるのか見てみよう。

public boolean isPrime(long number) {
  return number > 1 &&
    LongStream
    .rangeClosed(2, (long) Math.sqrt(number))
    .parallel()
    .noneMatch(index -> number % index == 0);
}
isPrime(9220000000000000039L) // Output: true

これだけ!.parallel()をストリームに追加しただけだ。ライブラリやランタイムが複雑さにいかに対処してくれるかがわかる。

階乗:命令型vs関数型

(nの階乗は、n以下の全ての正の整数の積)

反復および命令型形式での階乗

public long factorial(int n) {
  long product = 1;
  for ( int i = 1; i <= n; i++ ) {
    product *= i;
  }
  return product;
}
factorial(5) // Output: 120

反復および関数型形式での階乗

public long factorial(int n) {
 return LongStream
   .rangeClosed(1, n)
   .reduce((a, b) -> a *   b)
   .getAsLong();
}
factorial(5) // Output: 120

重要なので繰り返すが、方法の部分を抽象化することで、保守しやすくスケーラブルな ソフトウェアを書くことができる。

Java8の便利な関数型機能を全部見るには、以下のLambda Expressions, Method References and Streamsガイドを参照して欲しい。

原文:https://www.javacodegeeks.com/2015/12/functional-vs-imperative-programming-fibonacci-prime-factorial-java-8.html(2016-5-9)
※元記事の筆者には直接翻訳の許可を頂いて、翻訳・公開しております。

 -Tech, ,

FAworksではプロのコンサルタントが案件をお探しします

  関連記事

継続的デリバリがもたらす効果と価値とは~ソフトウェア業界全体の「対応力を高める」トレンドを追え~

継続的デリバリがもたらす効果と価値 ~ソフトウェア業界全体のトレンド “React” を追え~

あなたが「リリース」という言葉を聞いた時、どのような感情が呼び起こされるだろうか?安堵?高揚感?ある

NGINXのスレッドプールがパフォーマンスを9倍にする!

NGINXのパフォーマンスをスレッドプールで9倍にする

はじめに NGINXが接続処理に非同期かつイベント駆動のアプローチを用いていることは、よく知られてい

なぜあなたのインターネットは遅いのか?問題を切り分けて特定するトラブルシューティング

はじめに 家庭、コーヒーショップ、またはオフィスでの作業中に「インターネット(インフラ)にまつわる問

webを利用してイケてるガールにデプロイする方法

webを利用してイケてるガールにデプロイする方法

エンジニアに出会いはない。 彼らが業務で関わりを持つのは、チームのメンバーとPCのみ。 そしてそのメ

「AIって何?」なんて今さら聞けない!最低限抑えておきたいこれからの技術トレンド4つ(最新版)

【関連記事】 ❏これから必ず伸びる!最低限抑えておきたい技術トレンド3つ(2015年度版) ❏海外エ

エンジニアの作業効率を一気に上げてくれる、無料Google Chrome拡張機能おすすめ20選

ちょっとした時短の積み重ねが作業時間を減らしてくれる 情報収集やブラウザチェック、ルーティーンワーク

Linux OSのジッタを体系的に削減する黒魔術

Linux OSのジッタを体系的に削減する黒魔術

低遅延性の求められるトレードシステムにおいて、ジッタの原因をどのように体系的に発見してひとつずつ削除

待ち遠しい次の祝日がコマンドラインでわかる!‐cal‐ 端末にカレンダーを表示しよう

待ち遠しい次の祝日がコマンドラインでわかる!‐cal‐ 端末にカレンダーを表示しよう

これは“コマンドライン・マンデー”シリーズの最初の投稿です。このシリーズでは、毎週月曜日に使えるコマ

【2020年版】東京周辺で開催のエンジニア向け技術系カンファレンス日程まとめ【全64件!】

重要:新型コロナウイルス感染症の拡大により、多数のイベントが中止または延期を発表しています。 公式サ

フログラミングって知ってる?エクストリームな環境あれこれ

日々オフィスや自宅のデスクでプログラムを書く日々、なんだか煮詰まる、変わり映えがしない…と思っていま