fp

関数型 - パターンマッチ

 
パターンマッチのシナリオ:
  • 加減算を行うインタプリタ eval を実装する。
  • インタプリタは、手入力された抽象構文木(AST)を評価する。(5 + (7 - 9))
  • 手入力で AST を作成するメリットは、数式の字句解析と構文解析を省略できる点にある。
  • これにより、実装対象をインタプリタ(僅か10行ほど)に絞り込むことができる。
  • このインタプリタはパターンマッチの簡潔なサンプルとして優れている。
  • パターンマッチを使用すると、リストの分解など他にも面白いことができるが、今回のシナリオには含まれない。

Scala チュートリアル集

 
Scala のシンボル

Twitter のバックエンドとして知られるハイブリッド言語、 Scala のチュートリアルを集めました。

2009-11-07、1 件追加しました。
2009-09-16、1 件追加しました。
合計で 17 件あります。

関数型 - Yコンビネータ

 
Yコンビネータのシナリオ:
  • Yコンビネータ(こんな感じのやつ → Y(F) = F(Y(F)) )を無心に写経する。
  • サンプルとして fact(10) を計算する。
  • 変数名としても関数名としても、fact の名を冠するものは登場しない。

関数型 - メモ化 Memoization

 

SICP Exercise 3.27.

メモ化のシナリオ:
  • 高階関数 memoize は、引数で渡された関数に対して、計算結果のキャッシング機能を追加する。
  • memoize の戻り値はキャッシング機能付きの関数で、これを変数 fib を通して使用する。
  • キャッシング機能によって、計算量の爆発が抑えられることを確認する。
  • 具体的には fib(1000) を計算する! これは、メモ化されていない fib(30) よりも遙かに速い。
  • 計算結果の桁数が200桁を越えるので、可能であれば多倍長整数を使用する。

関数の実行時間を計測するには?

 
  • 処理系で用意されている方法があるなら、それを使用する。
  • 無ければ、関数の実行時間を計測する関数 time を作成する。
  • 計測対象のサンプル関数として、フィボナッチ数を計算する fib を作成する。
  • 計測単位は、可能な限り秒(sec)とする。
  • 計測精度はミリ秒でもマイクロ秒でも構わない。

並列処理 - フィボナッチ数を7個同時に計算

 

Erlangの並列処理を学ぶことでアクターモデルの理解ができた! に掲載されているコードは Scala で書かれていて、 Nのフィボナッチ数を計算するプロセスを 7本同時に走らせます。 そして、プロセスの開始順とは無関係に、 早く計算が終わったものから順に計算結果を表示していきます。 たとえ、一番最後に開始されたプロセスであっても、 Nが十分に小さければ一番最初に終了する可能性もあるわけです。

恐ろしく簡潔なコードです。 実際に走らせてみると、デュアルコアCPUの使用率が2個とも振り切れて、とても満足です。

$ scalac ActorTest.scala
$ scala ActorTest
fib[5]: 8
fib[10]: 89
fib[20]: 10946
fib[30]: 1346269
fib[40]: 165580141
fib[41]: 267914296
fib[42]: 433494437

ついでなので、Erlang 版も試してみましょう。 で、コードを見てみると、Scala 版に比べてプロセス間通信がスッキリしません。 ここは一つ、 Scala 版と1対1で対応する形で Erlang 版を書いてみます。

関数型 - イテレータ

 
イテレータのシナリオ:
  • 高階関数 myEach は、配列要素を1つ取り出すごとに、これを引数としてコールバックを行う。
  • 呼び出し側は、3の倍数を見つけたらプリントする。
  • myEach は、可能であれば組み込み型の拡張として実装する。 このとき継承は使わない。

処理系のインストール

 

記事で使用している処理系のインストール方法、 及びシェルの起動と終了について記載します。

関数型 - 無限リスト

 
無限リストのシナリオ:
  • 無限に続く奇数列 (1, 3, 5, 7, 9 ...)、odd を作成する。
  • 最初の10件を配列(リスト)に取り込む。

JavaScript とクロージャ

 

クロージャ は、1960年代に抽象プログラミング言語 ISWIM のVMである SECDマシン の機能として考案されました。 1970年代に入ると、このクロージャを実装した最初のプログラミング言語が登場します。 関数型言語の Scheme です。

1990年代に入ると、超高水準言語(VHLL)の一派である Ruby と JavaScript が、クロージャで完全武装して登場します。 あまりにも凄すぎて、その姿は誰にも見えませんでしたが、ついに2000年代に入って再発見されるのです!

2000年代に入ると、クロージャは C# や PHP にさえも実装され、もはや近代のプログラミング言語においては必須機能となりつつあります(Java への実装も提案されていますが、実現は難しそうです) 。

このような流れの中で、クロージャはクラス絶対主義に対して(プチ)パラダイムシフトをもたらす、なんてこともあるかも知れません。

本稿は、そんなクロージャについて書かれた記事へのリンク集です。 タイトルは「JavaScript とクロージャ」としましたが、JavaScript 以外の言語も含まれています。 

関数型プログラミング - 目次

 

これは、関数型プログラミングの記事をブック形式にまとめた集約エントリです。 難易度の低いものから高いものへと順にページをめくって行くことが出来ます。

関数型 - 有限リスト

 
有限リストのシナリオ:
  • 有限の奇数列 (1, 3, 5 .. 19) 、odd を作成する。
  • 可能であれば、 無限リストへの道筋となるような実装を行う。
  • 値を一気に配列(リスト)に取り込む。

関数型 - 再帰呼び出し

 
階乗の計算を、再帰呼び出しを使用して書く。
  • サンプル: 10 * 9 * 8 * 7 * 6 * 5 * 4 * 3 * 2 * 1 = 3628800
  • いずれの処理系でも、非末尾再帰と末尾再帰の 2バージョンを作成する。 処理系によっては、末尾再帰で記述すると最適化される。
  • パターンマッチを使用できる処理系では、これを使用する。 そうでなければ if-else に準ずる構文を使用する。

関数型 - クロージャ

 
クロージャのシナリオ:
  • 高階関数 foo は、ラムダ関数を返す。
  • このラムダ関数は、環境(foo の引数 keyword、foo のローカル変数 page)を記憶している。
  • 呼び出し側は、変数 f1 と f2 を通して、キーワードに対する検索結果のページを次々に取り出すことができる。

関数型 - コールバック

 
コールバックのシナリオ:
  • 定形処理(x ** 2)を行う高階関数 foo を作成する。
  • 差分処理(x * 2)を行うラムダ関数を作成する。
  • 高階関数 foo は、ラムダ関数をコールバックしたあと、両者の和を求める。