はてなキーワード: ghcとは
近年、関数型プログラミングの重要性はいろんなところで叫ばれています。
Javaの最新バージョンに関数型プログラミングに関する新機能が加わりました。
Rubyも昨今、関数型プログラミングへのサポートが手厚くなってきています。
プログラミングの教科書の大手、オライリー社から、Javascriptで関数型プログラミングを行うための解説書が発行されました。
関数型プログラミングへの注目度は高まってきています。
おそらく、みなさんは既にオブジェクト指向が何か、を知っています。
でも関数型プログラミングとは何か、胸を張って語れる人は、周りに見当たらないかと思います。
実際、オブジェクト指向によってプログラミングする方法は、わかりやすい解説があちこちにある一方で、
関数型プログラミングとは何か、何が良いのか、ということについての、よいまとめは見つけることはできませんでした。
この記事を読む方の中で、「関数型プログラミングを取り入れるか・取り入れないか」で切実に悩んでいる人は、おそらくいないでしょう。
この記事はあまり細かいところに立ち入りません。関数型プログラミングを使う側の立場に立って、利点や向き・不向き、それが導くスタイルを書きました。
みなさんは鳥のように飛んで、高い空から、関数型プログラミングとは何か、何が良いのか、を見渡してください。
オブジェクト指向的アプローチは、名前をつけてプログラムを整理する。
関数型プログラミング的アプローチは、汎用部品でなんとかする。
Googleが近年リリースした言語、Goには、”継承”を直接サポートする仕組みが無いことが話題になりました。
また、Mac OSXの基幹ライブラリCore Foundationは、ライブラリ自体はC言語で書かれているにもかかわらず、その設計方針は明確にオブジェクト指向です。
その本質とは"名前をつけて対象を識別し、それを扱うこと"、にあります。
最もプリミティブなオブジェクト指向の対象は、ファイルハンドラです。あるファイルを開いて、読み込んで、あるいは書き込んで、ファイルを閉じる。
これらの処理をまとめたら、わかりやすいですよね?
対象に関する処理を、対象の周りにまとめる。これがオブジェクト指向の基礎的な理念です。
識別することとイコールで比較できることは、とても良く似ています。
イコールによる比較は、オブジェクト指向では鬼門であることが知られています。
PointクラスのインスタンスとColoredPointクラスのイコール演算をどう決めればいいかに、正解はありません(詳しくは"effective java"をご参照ください)。
また名前をつけて識別する対象は、フワフワしていてはいけません。
たとえば、"軍人の階級"をオブジェクトにしたとしましょう。"大佐"クラスのある兵士は名前のフィールドや、性別のフィールドを持っているでしょう。
ところで彼が昇格したときに何が起こるでしょうか。
新たに"少将"クラスのインスタンスが作られます。"大佐"クラスを破棄する前に、名前、性別、その他沢山のデータを引き継がなくてはいけません。フィールドを増やしたい場合はその都度コードに修正を加える必要があります(*)。
なるべくイコール比較を避けたい。対象は不安定なものではいけない。では何に名前をつけて、識別するか。そこにオブジェクト指向技術者の熟練度が現れるのです。
一方、関数型プログラミングでは、特定の何かに名前をつけるより、極力、汎用部品でなんとかしようとします。
関数自体をリストなどのデータ構造に詰めることもよく行われます。
実は、関数型プログラミングというのは本質を表していません。
関数をはじめとして、リスト・ツリーのようなコンテナ、手続きを抽象化したもの、回路を抽象化したもの。
あらゆる対象を値として、合成し、ときに分解し、新しい値を作ります。
変数に適用する処理を作りあげることが、とても簡単だからです。
四則演算が定義されたデータを詰めたデータ構造もまた、四則演算可能だったり。
誤解を恐れずに言うと、オブジェクト指向がトップダウンなのに対し、関数型プログラミングはボトムアップです。
関数型プログラミングをサポートする言語には、沢山の汎用部品が定義されています。
このような構造をインターフェイスとして、様々なライブラリが組まれているので、
たとえばモナドを知っていれば、30分程度でパーサー(解析機)を理解することができて、
パーサーを理解できれば、JSONパーサー・ XMLパーサー・markdownパーサー・C++パーサー ... などを理解するのはとても容易です。
理解しやすいこと。これが関数型プログラミングの大きな利点です。
追記:
また、汎用部品と型のお陰で、ライブラリのドキュメントが圧倒的にひきやすい、というメリットも有ります。
Haskellな人がPythonにトライした結果 - Togetterまとめ
関数型プログラミングは「厳密な事前設計を必要とするため、簡単なことをやるのにも時間が掛かる」。
>> map (*2) [1,2,3] [2,4,6]
邪魔な”儀式”や、"おまじない"のコードが徹底的に撤廃されているためです。
関数型プログラミングのコードは、潔癖かつ濃密です。
たとえばC言語でint hoge(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.2 Prologプログラムの部分計算 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.4 GHCが与える並行計算の枠組み 1.4.1 GHCにおける計算とは,外界との情報のやりとり(通信)である 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 Temporal Prolog 2.8 RACCO 2.9 実現 2.10 まとめと参考文献案内 第3章 レコード・プログラミング (横田一正) 3.1 はじめに 3.2 レコードと述語の表現 3.3 レコード構造とφ-項 3.3.1 φ-項の定義 3.3.2 型の半順序と束 3.3.3 KBLとLOGIN 3.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 OBJ2 4.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 プログラミング・システム FP 5.2.1 オブジェクト 5.2.2 基本関数 5.2.3 プログラム構成子 5.2.4 関数定義 5.2.5 FPのプログラミング・スタイル 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.5 FPプログラムの翻訳 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 カテゴリカル・コンビネータ理論CCL 6.4 関数型プログラミングへの応用 6.4.1 関数型プログラミング言語ML/O 6.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.3 Knuth-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-Lisp 9.4 リフレクティブタワー 9.5 GHCにおけるリフレクション 9.5.1 並列論理型言語GHC 9.5.2 GHCの言語仕様 9.5.3 GHCのメタインタプリタ 9.5.4 リフレクティブ述語のインプリメント 9.6 まとめ
http://anond.hatelabo.jp/20070722124636
「本当に専門的な知識なんてネットに存在しないよ」というから「論文は専門的な知識じゃないの?」と言ったまでです。
http://anond.hatelabo.jp/20070722125013
本かぁ……。関数型言語のコンパイラの実装について語った日本語の本をずっと探しているんだけど、ないんだよねぇ。発売される気配すらしない。
んで、仕方なく英語の論文を紐解くわけだ。「 GHC ハッキングガイド」とか出たらマジで買う。
http://anond.hatelabo.jp/20070722125508
経験を得る為の指針として専門的な文献が必要なんです。