はてなキーワード:GHCとは
近年、関数型プログラミングの重要性はいろんなところで叫ばれています。
Javaの最新バージョンに関数型プログラミングに関する新機能が加わりました。
Rubyも昨今、関数型プログラミングへのサポートが手厚くなってきています。
プログラミングの教科書の大手、オライリー社から、Javascriptで関数型プログラミングを行うための解説書が発行されました。
関数型プログラミングへの注目度は高まってきています。
おそらく、みなさんは既にオブジェクト指向が何か、を知っています。
でも関数型プログラミングとは何か、胸を張って語れる人は、周りに見当たらないかと思います。
実際、オブジェクト指向によってプログラミングする方法は、わかりやすい解説があちこちにある一方で、
関数型プログラミングとは何か、何が良いのか、ということについての、よいまとめは見つけることはできませんでした。
この記事を読む方の中で、「関数型プログラミングを取り入れるか・取り入れないか」で切実に悩んでいる人は、おそらくいないでしょう。
この記事はあまり細かいところに立ち入りません。関数型プログラミングを使う側の立場に立って、利点や向き・不向き、それが導くスタイルを書きました。
みなさんは鳥のように飛んで、高い空から、関数型プログラミングとは何か、何が良いのか、を見渡してください。
オブジェクト指向的アプローチは、名前をつけてプログラムを整理する。
関数型プログラミング的アプローチは、汎用部品でなんとかする。
Googleが近年リリースした言語、Goには、”継承”を直接サポートする仕組みが無いことが話題になりました。
また、Mac OSXの基幹ライブラリCore Foundationは、ライブラリ自体はC言語で書かれているにもかかわらず、その設計方針は明確にオブジェクト指向です。
その本質とは"名前をつけて対象を識別し、それを扱うこと"、にあります。
最もプリミティブなオブジェクト指向の対象は、ファイルハンドラです。あるファイルを開いて、読み込んで、あるいは書き込んで、ファイルを閉じる。
これらの処理をまとめたら、わかりやすいですよね?
対象に関する処理を、対象の周りにまとめる。これがオブジェクト指向の基礎的な理念です。
識別することとイコールで比較できることは、とても良く似ています。
イコールによる比較は、オブジェクト指向では鬼門であることが知られています。
PointクラスのインスタンスとColoredPointクラスのイコール演算をどう決めればいいかに、正解はありません(詳しくは"effectivejava"をご参照ください)。
また名前をつけて識別する対象は、フワフワしていてはいけません。
たとえば、"軍人の階級"をオブジェクトにしたとしましょう。"大佐"クラスのある兵士は名前のフィールドや、性別のフィールドを持っているでしょう。
ところで彼が昇格したときに何が起こるでしょうか。
新たに"少将"クラスのインスタンスが作られます。"大佐"クラスを破棄する前に、名前、性別、その他沢山のデータを引き継がなくてはいけません。フィールドを増やしたい場合はその都度コードに修正を加える必要があります(*)。
なるべくイコール比較を避けたい。対象は不安定なものではいけない。では何に名前をつけて、識別するか。そこにオブジェクト指向技術者の熟練度が現れるのです。
一方、関数型プログラミングでは、特定の何かに名前をつけるより、極力、汎用部品でなんとかしようとします。
関数自体をリストなどのデータ構造に詰めることもよく行われます。
実は、関数型プログラミングというのは本質を表していません。
関数をはじめとして、リスト・ツリーのようなコンテナ、手続きを抽象化したもの、回路を抽象化したもの。
あらゆる対象を値として、合成し、ときに分解し、新しい値を作ります。
変数に適用する処理を作りあげることが、とても簡単だからです。
四則演算が定義されたデータを詰めたデータ構造もまた、四則演算可能だったり。
誤解を恐れずに言うと、オブジェクト指向がトップダウンなのに対し、関数型プログラミングはボトムアップです。
関数型プログラミングをサポートする言語には、沢山の汎用部品が定義されています。
このような構造をインターフェイスとして、様々なライブラリが組まれているので、
たとえばモナドを知っていれば、30分程度でパーサー(解析機)を理解することができて、
パーサーを理解できれば、JSONパーサー・ XMLパーサー・markdownパーサー・C++パーサー ... などを理解するのはとても容易です。
理解しやすいこと。これが関数型プログラミングの大きな利点です。
追記:
また、汎用部品と型のお陰で、ライブラリのドキュメントが圧倒的にひきやすい、というメリットも有ります。
Haskellな人がPythonにトライした結果 - Togetterまとめ
関数型プログラミングは「厳密な事前設計を必要とするため、簡単なことをやるのにも時間が掛かる」。
>> map (*2) [1,2,3][2,4,6]
邪魔な”儀式”や、"おまじない"のコードが徹底的に撤廃されているためです。
関数型プログラミングのコードは、潔癖かつ濃密です。
たとえばC言語でinthoge(int x,int y)が定義されているとき、hoge(3)はなんの意味も持ちませんが(コンパイルでコケますが)、関数型プログラミングでは意味があり、実際に有用です。
上の例では、「掛け算をする」(*)関数は、二引数関数ですが、それに引数を渡して作られた「2を掛ける」関数(*2)は、一引数関数になります。
関数型プログラミングでは、「簡単なことは簡単にでき、複雑なことは複雑にできる。ただし、間違ったことは殆どできないか、全くできない」。
また、静的型付けの力によって、コード補完は非常に強力になっています。インテリセンスの比ではないです。
たとえば、関数中のある表記の型を任意に表示できます(GHC/TypedHoles - HaskellWiki)。
やがてやってくる未来には、プログラムをテキストエディタで書くことは時代遅れになっているでしょう。
統合環境のサポートで、バグやミスの少ない、スムーズなプログラミングができます。
そしてその環境で動くプログラミング言語は、関数型プログラミングをサポートした言語なのです。
以下の様な兆候を感じたら、あなたはそのプログラムを関数型プログラミングで書くべきです。
一般に、オブジェクト同士の相互作用が複雑になるほど、オブジェクト指向では手に負えなくなっていきます。
そういうときは、オブジェクトを直接扱わず、替わりにその"相互作用"を扱うことで、複雑さを軽減するアプローチが有効です。
それこそが関数型プログラミング的アプローチです。
特にオブジェクト指向が有効なのは、プログラミング初心者がそのコードをいじるかもしれないときです。
関数型プログラミングは、強固さと柔軟さの代償として、高い学習コストを伴います。
オブジェクト間の相互作用が複雑でなく、着目している(名前をつけている)概念が安定しているとき。
そして、プログラムをいじる人たちの間で共通理解が図れているならば、オブジェクト指向が有利です。
遅延評価という機能によって、レガシーな言語で扱えなかった、巨大な数を扱うことができます。
関数型プログラミングで書かれたプログラムは、正確さが要求される、金融関連の業界で使われています。
手続きとしてパーサーを記述できるので、テキスト処理プログラムはより理解しやすく、メンテナンスしやすいものになります。
関数型プログラミングを知らない人は、「正規表現でおk」と言いますが、
彼の書いた複雑な正規表現は、半年後には(書いた本人でさえ)理解できなくなっていることでしょう。
手続き一般を扱うことができるので、途中で割り込みのある手続きの表現も容易です。
関数型プログラミングをサポートしていない言語ではコルーチン(ファイバー)などをつかってなんとかするしかありません。
さもなくば、非並行処理では普通に関数として記述できるところを、並行処理のために、Builder,Strategy,Command,Interpreterパターンを駆使して書き直すことになります。
Javascript使いの方は、Deferredなどの構造を使うでしょう(http://qiita.com/KDKTN/items/4c6986049d204f0645d8)。
C++使いの方はBoostで頑張りましょう。破滅的に解りにくいコンパイルエラーメッセージと格闘してください。
もう少し簡単な例をあげます。
あなたは、あるレシピにしたがって、自動的に料理を行うマシンの制御プログラムを書いているとしましょう。
1. まず玉ねぎを炒める。
2. 飴色になったら、肉を加えて炒める。
3.野菜を加える。
4. 水を加えて煮る。
5.スパイスを加える。
…できませんよね?何故ならば、各ステップの"間に"、マシンのロボアームの位置や動きを調整する処理が必要だからです。
これをオブジェクト指向でやろうとすると、各ステップの副作用として、それらの処理を行うことになります。
そうすると、マシンが二機に増えた時などの変更量は、絶望的なものになります。
あるいは関数として表現するのを諦め、手順全体をDSLで記述できるようにします。
このアプローチは関数型プログラミング的です。しかし関数型プログラミングをサポートした言語の助けなしでは、そのDSLを記述するために沢山のユーティリティーコードを書かなくてはならないでしょう。
オブジェクト指向的アプローチでこの問題をエレガントに解こうとすると、クラス化の粒度を上げる事になります。
野菜クラス、フライパンクラス、ボイルクラス、フライクラス、焼き加減クラス、アームクラス、野菜の大きさクラス、切り方クラス、焼き方クラス、"焦げたよ"クラス、etc...
こうすると早晩レシピはプログラムのコード上から消え去ることになります。上記のたった5行は、依存性注入のオブジェクトグラフを構築するコードに取って代わることになります。そこには沢山の挙動の制御がオプションとして付記されているのです。
カレーなど、ある種のレシピに限定することで、見た目の理解しやすさを得ることができますが、一方それは表現力を損なうことを意味します。
C言語などではマクロを使うこともできますが、それは結局、関数型プログラミング的アプローチの意味するところと同じになります。すなわち、補助のために沢山のコードを書くことになるでしょう。
iOSのAppstoreアプリは、"無料"と書かれたボタンを押すと、それが"インストール"ボタンに変わり、それをもう一度押すと、ダウンロードの進捗を表すインジケータに変わり、それを押すとダウンロードをキャンセルできます。
このように、位置は同じなのに、ステートに依って見た目と機能が変わるボタンは複雑です。
これをオブジェクト指向で実現しようとすると、
という下らない問題にぶつかります。
一方関数型では、"機能"、"見た目"、"状態"、を独立に扱って、それらを合成してボタンを作るので、迷うことはありません。
「同じ位置にあるUIオブジェクトは、コード上で(インスタンスとして)独立して、他から干渉を受けない」
この条件が満たされているうちは、オブジェクト指向でGUIを実現することに無理はありません。
しかし、携帯端末のような小さい画面で、多くの機能を達成するためには、UI要素はコンテキスト依存的に複雑になりがちです。
近年、PCのディスプレイの大きさは、頭打ちになってきました。
画素数は増えているのですが、MacにおけるRetinaのように、複数ピクセルでひとつのドットを表すようになってきています。
これは、ひとつの画面に置かれるボタンなどのUI要素の数は、これから先の未来で増えることはない、ということを意味します。
したがって、未来のGUIのプログラミングは、注意深く機能をピックアップして制限するというデザイナーの努力を脇におけば、
関数型プログラミングの力を頼るしか無いでしょう。
つまり…
Haskellさいこうなのおおおおおおおおおおおおおおおおおお!! おしっこ漏れちゃうのおおおおおおおおおおおおおおおおおおおお(゜∀。)ワヒャヒャヒャヒャヒャヒャ
1.google:すごいHaskellたのしく学ぼう を注文する。
2.Download Haskell を自分のPCに導入する。
3.コンソールにghciと入力して、対話型コンソールを立ち上げる。
4. 次の関数をコンソールに打ち込んで、結果を見る。即値で書かれているところとかをいろいろ変更してみて、感動する。
take 4 $ map (*2) [1..]
追記:
いかがでしたか?
ちまたには、関数型プログラミングの利点は変数が無いことだ、とか、より安全だから、とか、より速いから、などという妄言が満ち溢れています。
オブジェクト指向と関数型プログラミングは、水と油ではありません。プログラマは自分のプログラムに最適なアプローチを選ぶことができます。
一般にはあまり知られていないことですが、Haskellにもオブジェクト指向へのサポートがあるんです(Lensライブラリ、これを使用したサードパーティ製ライブラリも最近増えてきています)。
この記事を読んだオブジェクト指向プログラマのあなたが、少しでも関数型プログラミングに(そしてHaskellに)興味を持ってくださって、ホームセンターの大人用オシメのコーナーが大賑わいになれば幸いです。。
第1章 プログラム変換入門 佐藤泰介1.1 今なぜプログラム変換か?1.2 変換あれこれ1.3システム化について第2章 等式プログラムの等価変換 二木厚吉2.1等価変換例2.2等価性2.3等価変換法2.4 おわりに第3章 論理型言語におけるプログラム変換 玉木久夫3.1 はじめに3.2論理プログラムとその意味論3.3 展開/たたみ込み変換:例題3.4 展開/たたみ込み変換の正当性3.5 他の変換との両立性3.6 おわりに第4章 部分計算 二村良彦4.1 はじめに4.2 部分計算の概要4.3 部分計算の応用例4.4 部分計算の理論4.5実用化のための課題第5章 メタ・プログラミングと部分計算 竹内彰一5.1 はじめに5.2Prologプログラムの部分計算5.3メタ・プログラミングへの応用5.4メタ・インタプリタの段階的特殊化5.5 おわりに第6章 合成問題への新しいアプローチ 佐藤泰介6.1 否定技法6.2 二重否定技法6.3論理プログラムの合成第7章 ベクトル化とプログラム変換 安村通晃7.1 はじめに7.2プログラム変換7.3ベクトル化7.4 主要変換7.5 基軸変換7.6 その他の変換7.7ベクトル化におけるプログラム変換の特徴7.8 おわりに第8章 GHCでのプログラム変換 吉川康一8.1 はじめに8.2 簡単な問題8.3フィルタ・プロセスの融合8.4プログラム変換の手順8.5電子回路シミュレータへの応用8.6 おわりに第9章 実用規模プログラムの変換試行事例 吉田紀彦9.1 はじめに9.2コンパイラの変換9.3プログラム変換の実用可能性9.4 おわりに
第1章 並行プログラミングとGHC (上田和紀)1.1 はじめに1.2ターゲットを明確にしよう1.3 はじめが大切1.4GHCが与える並行計算の枠組み1.4.1GHCにおける計算とは,外界との情報のやりとり(通信)である1.4.2計算を行う主体は,互いに,および外界と通信し合うプロセスの集まりである1.4.3プロセスは,停止するとは限らない1.4.4プロセスは,開いた系(open system)をモデル化する1.4.5情報とは変数と値との結付き(結合)のことである1.4.6プロセスは,結合の観測と生成を行う1.4.7プロセスは,書換え規則を用いて定義する1.4.8 通信は,プロセス間の共有変数を用いて行う1.4.9外貨も,プロセスとしてモデル化される1.4.10 通信は,非同期的である1.4.11プロセスのふるまいは,非決定的でありうる1.5 もう少し具体的なパラダイム1.5.1ストリームと双方向通信1.5.2 履歴のあるオブジェクトの表現1.5.3データ駆動計算と要求駆動計算1.5.4 モジュラリティと差分プログラミング1.5.5プロセスによるデータ表現1.6歴史的背景と文献案内1.7 並行プログラミングと効率1.8 まとめ第2章 様相論理とテンポラル・プログラミング (桜川貴司)2.1 はじめに2.2 様相論理2.3 時制論理2.4 多世界モデル2.5 到達可能性と局所性2.6 純論理プログラミングへ向けて2.7 TemporalProlog2.8 RACCO2.9 実現2.10 まとめと参考文献案内第3章レコード・プログラミング (横田一正)3.1 はじめに3.2レコードと述語の表現3.3レコード構造とφ-項3.3.1 φ-項の定義3.3.2 型の半順序と束3.3.3KBLとLOGIN3.4 応用――データベースの視点から3.4.1演繹データベース3.4.2レコード・プログラミングとデータベース3.4.3 いくつかの例3.5 まとめ3.6 文献案内第4章抽象データ型とOBJ2 (二木厚吉・中川 中)4.1 はじめに4.2抽象データ型と代数型言語4.2.1抽象データ型4.2.2代数型言語4.2.3 始代数4.2.4 項代数4.2.5 項書換えシステム4.3 OBJ24.3.1 OBJ2の基本構造4.3.2モジュールの参照方法4.3.3 混置関数記号4.3.4モジュールのパラメータ化4.3.5パラメータ化機構による高階関数の記述4.3.6 順序ソート4.3.7属性つきパターンマッチング4.3.8 評価戦略の指定4.3.9モジュール表現4.4 おわりに第5章プログラム代数とFP (富樫 敦)5.1 はじめに5.2プログラミング・システム FP5.2.1オブジェクト5.2.2 基本関数5.2.3プログラム構成子5.2.4関数定義5.2.5FPのプログラミング・スタイル5.3プログラム代数5.3.1プログラム代数則5.3.2代数則の証明5.3.3代数則とプログラム5.4ラムダ計算の拡張5.4.1ラムダ式の拡張5.4.2拡張されたラムダ計算の簡約規則5.4.3 そのほかのリスト操作用演算子5.4.4 相互再帰的定義式5.4.5ストリーム(無限リスト)処理5.5FPプログラムの翻訳5.5.1オブジェクトの翻訳5.5.2 基本関数の翻訳5.5.3プログラム構成子の翻訳5.5.4 簡約規則を用いた代数則の検証5.6 おわりに第6章カテゴリカル・プログラミング (横内寛文)6.1 はじめに6.2 値からモルフィズムへ6.3カテゴリカル・コンビネータ6.3.1ラムダ計算の意味論6.3.2 モルフィズムによる意味論6.3.3カテゴリカル・コンビネータ理論CCL6.4関数型プログラミングへの応用6.4.1関数型プログラミング言語ML/O6.4.2 CCLの拡張6.4.3 CCLに基づいた処理系6.4.4公理系に基づいた最適化6.5 まとめ第7章最大公約数――普遍代数,多項式イデアル,自動証明におけるユークリッドの互除法 (外山芳人)7.1 はじめに7.2 完備化アルゴリズム7.2.1 グラス置換えパズル7.2.2 リダクションシステム7.2.3 完備なシステム7.2.4 完備化7.2.5パズルの答7.3普遍代数における完備化アルゴリズム7.3.1群論の語の問題7.3.2 群の公理の完備化7.3.3Knuth-Bendix完備化アルゴリズム7.4多項式イデアル理論における完備化アルゴリズム7.4.1ユークリッドの互除法7.4.2多項式イデアル7.4.3 Buchbergerアルゴリズム7.5 一階述語論理における完備化アルゴリズム7.5.1 レゾリューション法7.5.2 Hsiangのアイデア7.6 おわりに第8章 構成的プログラミング (林 晋)8.1 構成的プログラミング?8.2 型付きラムダ計算8.3論理としての型付きラムダ計算8.4 構成的プログラミングとは8.5 構成的プログラミングにおける再帰呼び出し8.6 おわりに:構成的プログラミングに未来はあるか?第9章メタプログラミングとリフレクション (田中二郎)9.1 はじめに9.2計算システム9.2.1因果結合システム9.2.2メタシステム9.2.3リフレクティブシステム9.3 3-Lisp9.4リフレクティブタワー9.5GHCにおけるリフレクション9.5.1 並列論理型言語GHC9.5.2GHCの言語仕様9.5.3GHCのメタインタプリタ9.5.4リフレクティブ述語のインプリメント9.6 まとめ
http://anond.hatelabo.jp/20070722124636
「本当に専門的な知識なんてネットに存在しないよ」というから「論文は専門的な知識じゃないの?」と言ったまでです。
http://anond.hatelabo.jp/20070722125013
本かぁ……。関数型言語のコンパイラの実装について語った日本語の本をずっと探しているんだけど、ないんだよねぇ。発売される気配すらしない。
んで、仕方なく英語の論文を紐解くわけだ。「GHCハッキングガイド」とか出たらマジで買う。
http://anond.hatelabo.jp/20070722125508
経験を得る為の指針として専門的な文献が必要なんです。