hotchpotch/wikipedia-multilingual-ir-pairs huggingface dataset:
関数型プログラミング
関数型プログラミング（かんすうがたプログラミング、英: functional programming）とは、数学的な意味での関数を主に使うプログラミングのスタイルである。 functional programming は、関数プログラミング（かんすうプログラミング）などと訳されることもある。
関数型プログラミング言語（英: functional programming language）とは、関数型プログラミングを推奨しているプログラミング言語である。略して関数型言語（英: functional language）ともいう。
関数型プログラミング 概要
関数型プログラミングは、関数を主軸にしたプログラミングを行うスタイルである。ここでの関数は、数学的なものを指し、引数の値が定まれば結果も定まるという参照透過性を持つものである。
参照透過性とは、数学的な関数と同じように同じ値を返す式を与えたら必ず同じ値を返すような性質である。次の square 関数は、 2 となるような式を与えれば必ず 4 を返し、 3 となるような式を与えれば必ず 9 を返し、いかなる状況でも別の値を返すということはなく、これが参照透過性を持つ関数の一例となる。
次の countup 関数は、同じ 1 を渡しても、それまでに countup 関数がどのような引数で呼ばれていたかによって、返り値が 1, 2, 3, ... と変化するため、引数の値だけで結果の値が定まらないような参照透過性のない関数であり、数学的な関数とはいえない。
関数型プログラミングは、参照透過性を持つような数学的な関数を使って組み立てた式が主役となる。別の箇所に定義されている処理を利用することを、手続き型プログラミング言語では「関数を実行する」や「関数を呼び出す」などと表現するが、関数型プログラミング言語では「式を評価する」という表現も良く使われる。
関数型プログラミング 概要
参照透過性とは、同じ値を与えたら返り値も必ず同じになるような性質である。参照透過性を持つことは、その関数が状態を持たないことを保証する。状態を持たない数学的な関数は、並列処理を実現するのに適している。関数型プログラミング言語の内で、全ての関数が参照透過性を持つようなものを純粋関数型プログラミング言語という。
関数型プログラミングでは、数学的な関数を組み合わせて計算を表現するが、それだけではファイルの読み書きのような外界とのやり取りを要する処理を直接的に表現できない。このような外界とのやり取りを I/O (入出力) と呼ぶ。数学的な計算をするだけ、つまり 1 + 1 のようなプログラム内で完結する処理ならば、入出力を記述できなくても問題ないが、現実的なプログラムにおいてはそうでない。
非純粋な関数型プログラミング言語においては、式を評価すると同時に I/O が発生する関数を用意することで入出力を実現する。たとえば、 F# 言語では、printfn "Hi." が評価されると、 () という値が戻ってくると同時に、画面に Hi. と表示される I/O が発生する。
関数型プログラミング 概要
Haskell では、評価と同時に I/O が行われる関数は存在しない。たとえば、 putStrLn "Hi." という式が評価されると IO () 型を持つ値が返されるが画面には何も表示されず、この値が Haskell の処理系によって解釈されて初めて画面に Hi. と表示される。 I/O アクションとは、ファイルの読み書きやディスプレイへの表示などのような I/O を表現する式のことである。 IO a という型は、コンピュータへの指示を表す I/O アクションを表現している。ここでの IO はモナドと呼ばれるものの一つである。
Clean では、一意型を用いて入出力を表す。
最初に解の集合となる候補を生成し、それらの要素に対して1つ（もしくは複数）の解にたどり着くまで関数の適用とフィルタリングを繰り返す手法は、関数型プログラミングでよく用いられるパターンである。
Haskell では、関数合成の二項演算子を使ってポイントフリースタイルで関数を定義することができる。関数をポイントフリースタイルで定義すると、データより関数に目が行くようになり、どのようにデータが移り変わっていくかではなく、どんな関数を合成して何になっているかということへ意識が向くため、定義が読みやすく簡潔になることがある。関数が複雑になりすぎると、ポイントフリースタイルでは逆に可読性が悪くなることもある。
関数型プログラミング 概要
関数型プログラミング言語とは、関数型プログラミングを推奨しているプログラミング言語である。略して関数型言語ともいう。全ての関数が参照透過性を持つようなものを、特に純粋関数型プログラミング言語という。そうでないものを非純粋であるという。
関数型プログラミング言語の多くは、言語の設計において何らかの形でラムダ計算が関わっている。ラムダ計算はコンピュータの計算をモデル化する体系の一つであり、記号の列を規則に基づいて変換していくことで計算が行われるものである。
C 言語や Java 、 JavaScript 、 Python 、 Ruby などの2017年現在に使われている言語の多くは、手続き型の文法を持っている。そのような言語では、文法として式 (expression) と文 (statement) を持つ。ここでの式は、計算を実行して結果を得るような処理を記述するための文法要素であり、加減乗除や関数呼び出しなどから構成されている。ここでの文は、何らかの動作を行うようにコンピュータへ指示するための文法要素であり、条件分岐の if 文やループの for 文と while 文などから構成されている。手続き型の文法では、式で必要な計算を進め、その結果を元にして文でコンピュータ命令を行うという形で、プログラムを記述する。このように、手続き型言語で重要なのは文である。
関数型プログラミング 概要
それに対して、関数型言語で重要なのは式である。関数型言語のプログラムはたくさんの式で構成され、プログラムそのものも一つの式である。たとえば、 Haskell では、プログラムの処理の記述において文は使われず、外部の定義を取り込む import 宣言も処理の一部として扱えない。関数型言語におけるプログラムの実行とは、プログラムを表す式の計算を進めて、その結果として値 (value) を得ることである。式を計算することを、評価する (evaluate) という。
手続き型言語ではコンピュータへの指示を文として上から順に並べて書くのに対して、関数型言語では数多く定義した細かい式を組み合わせてプログラムを作る。手続き型言語では文が重要であり、関数型言語では式が重要である。
式と文の違いとして、型が付いているかどうかというのがある。式は型を持つが、文は型を持たない。プログラム全てが式から構成されていて、強い静的型付けがされているのならば、プログラムの全体が細部まで型付けされることになる。このように細部まで型付けされているようなプログラムは堅固なものになる。
関数型プログラミング 歴史
関数型言語の開発において、アロンゾ・チャーチが1932年と1941年に発表したラムダ計算の研究ほど基本的で重要な影響を与えたものはない。ラムダ計算は、それが考え出された当時はプログラムを実行するようなコンピュータが存在しなかったためにプログラミング言語として見なされなかったにもかかわらず、今では最初の関数型言語とされている。1989年現在の関数型言語は、そのほとんどがラムダ計算に装飾を加えたものとして見なせる。
1960年にジョン・マッカーシー等が発表した LISP は関数型言語の歴史において重要である。ラムダ計算は LISP の基礎であると言われるが、マッカーシー自身が1978年に説明したところによると、匿名関数を表現したいというのが最初にあって、その手段としてマッカーシーはチャーチのラムダ計算を選択したに過ぎない。
関数型プログラミング 歴史
歴史的に言えば、 LISP に続いて関数型プログラミングパラダイムへ刺激を与えたのは、1960年代半ばのピーター・ランディンの成果である。ランディンの成果はハスケル・カリーとアロンゾ・チャーチに大きな影響を受けていた。ランディンの初期の論文は、ラムダ計算と、機械および高級言語 (ALGOL 60) との関係について議論している。ランディンは、1964年に、 SECD マシンと呼ばれる抽象的な機械を使って機械的に式を評価する方法を論じ、1965年に、ラムダ計算で ALGOL 60 の非自明なサブセットを形式化した。1966年にランディンが発表した ISWIM（If You See What I Mean の略）という言語（群）は、間違いなく、これらの研究の成果であり、構文や意味論において多くの重要なアイデアを含んでいた。 ISWIM は、ランディン本人によれば、「 LISP を、その名前にも表れたリストへのこだわり、手作業のメモリ割り当て、ハードウェアに依存した教育方法、重い括弧、伝統への妥協、から解放しようとする試みとして見ることができる」。関数型言語の歴史において ISWIM は次のような貢献を果たした。
関数型プログラミング 歴史
ランディンは「それをどうやって行うか」ではなく「それの望ましい結果とは何か」を表現することに重点を置いており、そして、 ISWIM の宣言的なプログラミング・スタイルは命令的なプログラミング・スタイルよりも優れているというランディンの主張は、今日まで関数型プログラミングの賛同者たちから支持されてきた。その一方で、関数型言語への関心が高まるまでは、さらに10年を要した。その理由の一つは、 ISWIM ライクな言語の実用的な実装がなかったことであり、実のところ、この状況は1980年代になるまで変わらなかった。
ケネス・アイバーソンが1962年に発表した APL は、純粋な関数型プログラミング言語ではないが、その関数型的な部分を取り出したサブセットがラムダ式に頼らずに関数型プログラミングを実現する方法の一例であるという点で、関数型プログラミング言語の歴史を考察する際に言及する価値はある。実際に、アイバーソンが APL を設計した動機は、配列のための代数的なプログラミング言語を開発したいというものであり、アイバーソンのオリジナル版は基本的に関数型的な記法を用いていた。その後の APL では、いくつかの命令型的な機能が追加されている。
Haskell
Haskell（ハスケル）は非正格な評価を特徴とする純粋関数型プログラミング言語である。名称は数学者であり論理学者であるハスケル・カリーに由来する。
Haskell 概要
Haskell は高階関数や静的多相型付け、定義可能な演算子、例外処理といった多くの言語で採用されている現代的な機能に加え、パターンマッチングやカリー化、リスト内包表記、ガードといった多くの特徴的な機能を持っている。また、遅延評価や再帰的な関数や代数的データ型もサポートしているほか、独自の概念として圏論のアイデアを利用し参照透過性を壊すことなく副作用のある操作（例えば 代入、入出力、配列など）を実現するモナドを含む。このような機能の組み合わせにより、手続き型プログラミング言語では記述が複雑になるような処理がしばしば簡潔になるばかりではなく、必要に応じて手続き型プログラミングを利用できる。
Haskell は関数型プログラミングの研究対象として人気が高い。あわせて Parallel Haskell と呼ばれるマサチューセッツ工科大学やグラスゴー大学によるものをはじめ、他にも Distributed Haskell や Eden といった分散バージョン、Eager Haskell と呼ばれる投機的実行バージョン、Haskell++ や O'Haskell、Mondrian といったオブジェクト指向バージョンも複数存在しているなど、いくつもの派生形が開発されてきている。
Haskell 概要
GUI開発向けサポートの新しい方法を提供する、Concurrent Clean と呼ばれる Haskell に似た言語もある。Haskell と Concurrent Clean の最大の違いは、モナドを代用する一意型の採用である。
Haskell は比較的小規模なユーザコミュニティを持つが、その力はいくつかのプロジェクトで十分に生かされてきた。オードリー・タンによる Pugs は Perl6 のインタプリタとコンパイラの実装で、書くのにたったの数ヶ月しかかからなかったなど Haskell の有用性を証明するものである（現在は開発停止）。Darcs はさまざまな革新的な機能を含むリビジョンコントロールシステムである。Linspire Linux は Haskell をシステムツール開発に選択した。
Haskell 概要
Haskell の急速な進化は今も継続しており、Glasgow Haskell Compiler（GHC）は現在の事実上の標準の処理系であるといえる。
ICFP Programming Contestでは2001、2004、2005、2010、2013、2014、2015、2016年に最優秀賞に選ばれている。
Cabal は Haskell 用のビルドおよびパッケージングシステムである。Cabal を利用して Haskell ライブラリのアーカイブである Hackage を参照して、新たなパッケージを簡単にインストールすることもできる。しばしばパッケージの依存関係地獄が発生しがちだが、それらを解決するため、Stackという環境も有志によって提供されている。
Haskell 歴史
1985年、遅延関数言語である Miranda がリサーチ・ソフトウェア社によって発表された。1987年にはこのような非正格な純粋関数型プログラミング言語が十二以上存在していたが、そのうち最も広く使われていた Miranda はパブリックドメインではなかった。オレゴン州ポートランドで開催された Functional Programming Languages and Computer Architecture (FPCA '87) において開かれた会議中に、遅延関数型言語のオープンな標準を作成するための委員会が発足されるべき、という強い合意が参加者のあいだで形成された。委員会の目的は、関数型言語のデザインにおける将来の研究のための基礎として役立つ共通のものへと、既存の関数型言語を統合することであった。
最初の版の Haskell（Haskell 1.0）は1990年に作成された。委員会の活動は一連の言語仕様を結果に残し、1997年後半にそのシリーズは、安定しており小さく可搬なバージョンの言語仕様と、学習用および将来の拡張の基礎としての基本ライブラリなどを定義したHaskell 98 に到達した。実験的な機能の付加や統合を通じて Haskell98 の拡張や派生物を作成することを、委員会ははっきりと歓迎した。
Haskell 歴史
1999年2月、Haskell 98 言語標準は最初に The Haskell 98 Report として発表された。2003年1月、改定されたバージョンが Haskell 98 Language and Libraries: The Revised Report として発表された。GHC に代表されるように、Haskell は急速に発達しつづけている。
2006年前半、非公式に Haskell′（Haskell Prime）と呼ばれている Haskell 98 standard の後継の作成プロセスが開始された。このプロセスは Haskell 98 のマイナーバージョンアップを目的としている。
Haskell 歴史
Haskell 2010 は他のプログラミング言語とのバインディングを可能にする Foreign Function Interface（FFI）を Haskell に追加し, いくつかの構文上の問題を修正する(正式な構文を変更する)。「n + k パターン」と呼ばれる構文を削除し, fak (n+1) = (n+1) * fak nというような形式の定義はもはや許されない。Haskell に Haskell 2010 のソースかどうかや, いくつかの必要な拡張の指定を可能にする言語プラグマ構文拡張を導入する。Haskell 2010 に導入された拡張の名前は, DoAndIfThenElse, HierarchicalModules（階層化ライブラリ）, EmptyDataDeclarations, FixityResolution, ForeignFunctionInterface, LineCommentSyntax, PatternGuards, RelaxedDependencyAnalysis, LanguagePragma, NoNPlusKPatterns である。
Haskell 主な構文
ここでは以降の解説を読む上で必要な Haskell の文法規則を簡単に説明する。Haskell の構文は数学で用いられるものによく似せられていることに注意されたい。
Haskell の型名は先頭が大文字でなければならない。標準で存在する単純なデータ型としては、Bool（真偽値）型、Int（整数）型、Float（単精度浮動小数点数）型、Char（文字）型、String（文字列）型などが予め定義されている。任意の式の型を定義するには、式と型の間に :: 記号をおく。また、変数などのシンボルを定義する際に変数名を式に指定して書くことで、その変数の型を指定することができる。例えば、次は円周率およびネイピア数を定数として定義し、さらにその型も浮動小数点型として指定している。
関数の型は、各引数の間を -> 記号で区切って表記する。関数は引数をひとつ適用するたびに、その型は -> で区切られたうちの一番左が消えた型となると考えればよい。例えば、ふたつの整数を引数にとりその最大公約数を返す関数 gcd の型は次のように定義される。
Haskell 主な構文
型変数を使い、型を抽象化することもできる。これは C++ のテンプレートや Java のジェネリクスに相当するが、様々な種(型の型)に適用できるためより柔軟である。例えば、a 型の値をとり、それをそのまま返す恒等関数 id を型の指定とともに定義すると以下のようになる。ここで任意の型を示す型名 a が定義に使われているが、このように先頭が小文字で始まっている型名は具体的な型名ではなく型変数である。この関数はあらゆる型の値を引数にとることができる。
また、データ型はパラメータとして型変数を持つことができる。例えば、スタックやハッシュテーブルなどのデータ型は、その要素の型を型変数として定義する。ハッシュテーブルを実装するデータ型 HashMap :: * -> * -> * があり、キーに文字列（String）、値に整数（Int）を持つハッシュテーブル hashtable の型は次のようになる。
Haskell 主な構文
そのほか、特殊な表記を持つ型としてリストとタプル、文字列がある。リストは Haskell で極めて頻繁に用いられるため、特別な構文が用意されている。リストは要素の型を角括弧で囲む。次は Char（文字）のリストを束縛する変数 text の定義である。文字のリストは文字列と等価である。2行目にあるように、文字列は殆どのプログラミング言語と同じように二重引用符で囲む。コメントにHaskellでのリストの表記を添えた。最後にデシュガー（糖衣構文を元の表記に戻すこと）したリストの表記法を示した。textもhelloも等価である。
タプルは要素の型をカンマで区切り、括弧で囲む。次は Float（浮動小数点数）の値をもつ2次元座標のタプルが束縛される変数 point の定義である。
タプルは2以上ならいくつでも要素を持つことができる。1要素のタプルは優先順位の括弧と表記が衝突し、また用途がないので存在しない。要素数がゼロのタプルは特に「ユニット」(Unit) と呼ばれ、有効な値を持たないなどの時に使われる。
type キーワードを用いて、型に別名をつけることができる。次は [Char] に String という別名をつけている。
Haskell 主な構文
Haskellの型は型構築子（型コンストラクタ、type constructor）から構築される。型構築子Tに型変数（Type variables）v1 v2 vNを与え型式（type expression）T v1 v2 vNとして評価することで型が構築される。型構築子の例には以下が挙げられる。
例えば型構築子Maybeに型変数Intを渡し、Maybe Intとすることで型が構築される。
関数名は先頭が小文字でなければならず、記号を含むことはできない。演算子名は記号のみで構成されていなければならない。関数の定義ではC言語のような引数を囲む括弧や区切りのカンマは使われず、単に引数を空白文字で区切って表記する。次は先程示した恒等関数 id に、型の定義に加えて本体の定義もした例である。
関数の適用も同様で、単に関数に続いて空白文字で区切った引数を並べればよい。以下では上記の恒等関数 id を(ここでは使う必要はないが)適用して、別の変数を定義した例である。
引数がつねに2個であることや引数の間に演算子をおくことなどを除けば、演算子についても関数の定義や適用と同様である。標準で定義されている算術演算子を使って、BMIを計算する関数 bmi を定義してみる。
この定義では Float を引数にとり Float で結果を返すが、この関数では Double を引数に使うことはできない。どの浮動小数点数型でも扱えるような関数にするには、次のように型変数を使えばよい。
このバージョンの関数 bmi では引数や返り値の型が a とされているが、これにさらに a は Floating であるとの制約をつけている。Floating は Float や Double を抽象化する型クラスであり / や ^  といった演算子を適用できるので、bmi の定義においてこれらの演算子を使うことができている。また、整数などの値は引数に取れないし、返り値は引数に与えた型で戻ってくる。
関数と演算子は新たに定義し直さなくても相互に変換可能である。関数を演算子として使うには、関数を ` (バッククォート)で囲む。逆に、演算子を関数として使うには括弧で囲む。例えば、整数を除算する関数 div はよく演算子として使われる。
なお、関数適用の優先順位はすべての演算子の優先順位よりも高い。
Haskell 特徴的な機能
ここではあまり他の言語では見られない Haskell 特有の機能を中心に解説する。ここでは説明していないが、現代的な実用言語では常識となっているガーベジコレクション、例外処理、モジュール、外部関数の呼び出し、正規表現ライブラリなどの機能は、Haskell にも当然存在している。
Haskell は遅延評価を基本的な評価戦略とする。ほとんどの言語では関数の呼び出しにおいて引数に与えられたすべての式を評価してから呼び出された関数に渡す先行評価を評価戦略とするが、これに対し Haskell ではあらゆる式はそれが必要になるまで評価されない。次の定数 answer は評価すると常に 42 を返すが、その定義には未定義の式を含む。
Haskell 特徴的な機能
ここで、const は常に第1引数を返す定数関数である。また、`div` は整数の除算を行う演算子であり、1 `div` 0 は 1 / 0 に相当し、この値は未定義であり、この部分を評価すればエラーになる。正格評価をする言語でこのような式を評価しようとすると、ゼロ除算によるエラーになるであろう。しかし 上記の定数 answer を評価してもエラーにはならない。const は第1引数をつねに返すので第2引数を評価する必要はなく、第2引数に与えられた式 1 `div` 0 は無視されるので評価されないからである。遅延評価がデフォルトで行われることにより、不要な計算は省かれ、参照透過性により同じ式を複数回評価する必要もなくなるため、Haskell では最適化によって計算効率の向上が期待できる場合がある。ただし、頻繁に新たな値を計算する場合は正格評価のほうが効率がよく、必要に応じてseq関数やBangPatterns拡張による明示により正格評価もできる。
Haskell では関数のデータ型を明示しなくても処理系が自動的に型を推論する。以下は型の宣言を省略し、本体のみを宣言した引数の平方を返す関数 square である。
この場合 square の型は型推論され、次のように明示的に型を宣言したのと同じになる。
Haskell 特徴的な機能
この宣言は、「Numのインスタンスである a の型の値を引数にとり、a の型の値を返す」と読める。ここでは「*」演算子が適用可能な最も広い型である Num a が選択されており、整数や浮動小数点数、有理数のような Num のインスタンスであるあらゆる型の値を渡すことができる。外部に公開するような関数を定義するときは、型推論によって自動的に選択される最も広い型では適用可能な範囲が広すぎる場合もある。Integer のみを渡せるように制限する場合は、次のように明示的に型を宣言すればよい。
型推論のため、Haskell は型安全でありながらほとんどの部分で型宣言を省略できる。なお、次のコードは型宣言が必要な例である。read は文字列をその文字列があらわすデータ型に変換する抽象化された関数である。
このコードはコンパイルエラーになる。read は複数のインスタンスで実装されており、数値なら数値型に変換する read、リストならリストに変換する read というように型ごとに実装が存在する。Haskell の型は総て静的に決定されなければならない。このコード場合、プログラマは
Haskell 特徴的な機能
という型をもつ実装の read が選択されると期待しているであろうが、これはコンパイラによる静的な型検査では決定できない。つまり、Haskell コンパイラは read の返り値を受け取っている関数 print の型を検査し多数の実装の中から適切な read を選択しようとするが、print は Show のインスタンスが存在するあらゆる型を引数にとるため、型推論によっても read の型を一意に決定できない。これを解消するひとつの方法は、:: によって型を明示することである。
また、そもそも read の返り値を整数型しか取らない関数に与えていればあいまいさは生じず、型推論は成功する。
他の言語、たとえば Java でこのような抽象的な関数を書こうとしても、Java では返り値の値の型によって関数を選択するようなことはできない（引数の型によって選択するメソッドのオーバーロードは存在する）。そのため、関数の実装ごとに別の名前をつけてプログラマに明示的に選択させて解決させることになる。この方法は簡潔でわかりやすいが、抽象性の高さに基づく再利用性という点では Haskell のような多相には劣ってしまう。
Haskell 特徴的な機能
Haskell のデータ型には代数的データ型と呼ばれる、C言語などでいう構造体や列挙体の性質を兼ね備えたものが用いられる。次の例は二つのInt型の値をフィールドに持つ二次元の座標、Point2D 型を定義したもので、これは代数的データ型の構造体的な性質を示す。先頭のトークン「data」は代数的データ型の宣言であることを示す予約語である。ここで最初の Point2D はデータ型名を表し、次の Point2D はデータコンストラクタ名を示す。
データコンストラクタは値を定義するための特殊な関数といえる。データコンストラクタは後述するパターンマッチによって値を取り出す際にも用いられる。
次の例はトランプの4つのスーツを示す Suit 型を定義したものである。Spade、Heart、Club、Diamond の4つのデータコンストラクタが定義されており、Suit 型の式は Spade、Heart、Club、Diamond のいずれかの値をとる。
次の例は String 型の値を格納する二分木の型である。Leaf（葉）は String 型の値を持ち、Branch（枝）は Leaf もしくは Branch である Tree 型の変数を二つ持つ。これは代数的データ型の構造体的な性質と列挙体的な性質の両方が現れている。
Haskell 特徴的な機能
GADTと呼ばれる機能を使うと、コンストラクタの型を明示してデータ型を定義することもできる。
Haskell は第一級関数をサポートしており、高階関数を定義することができる。つまり、関数の引数として関数を与えたり、返り値として関数を返すことができる。無名関数は \ (バックスラッシュ)から始まり、それに続いて引数となる変数、引数と本体のあいだに -> 記号をおく。List モジュールに定義されているリストのソートを行う関数 sortBy は、二つの要素に大小関係を与える関数を引数にとるが、無名関数を使うと例えばリストをその長さの短い順にソートする関数 sortList は次のように定義できる。
Haskell において、2つの引数を持つ関数は、1つの引数をとり「1つの引数をとる関数」を返す関数と同義である。このように、関数を返すことで全ての関数を1つの引数の関数として表現することをカリー化という。(あえてタプルを使うことで複数の引数を渡すような見かけにすることもできるが。)次の例は2つの引数をとり、そのうち値が大きい値を返す関数 max である。
この関数maxは無名関数を用いて次のように書き換えることができる。先ほどの表現とまったく同様に動作するが、この表現では関数を返す様子がより明らかになっている。
さらに、次のようにも書き換えることができる。
Haskell 特徴的な機能
あるいは、f x = ... x ... は、 f = (\x -> ... x ...) の糖衣構文であるとも言える。このため、Haskell の定義は変数に束縛するのが定数であるか関数であるかにかかわらず、「変数 = 値」という一貫した形でも定義できる。
カリー化によって、Haskell のあらゆる関数は引数を部分適用することができる。つまり、関数の引数の一部だけを渡すことで、一部の変数だけが適用された別の関数を作り出すことができる。また、Haskell では演算子を部分適用することすら可能であり、演算子の部分適用をとくにセクションと呼ぶ。
任意のリストをとり、その要素から条件にあう要素のみを取り出す関数 filter が標準ライブラリに定義されている。
この関数では第一引数に残す要素を判定する関数をとるが、このときに部分適用を使えばそのような関数を簡潔に書くことができる。整数のリストから正の値のみを取り出す関数 positives は次のように定義できる。
ここで、positives および filter の第2引数はソースコード上に現れずに記述できているが、このように単純に書けるのもカリー化の恩恵によるものである。
Haskell では関数の引数を様々な形で受け取ることができる。
次は整数の要素をもつリストの全要素の合計を返す関数 total である。
Haskell 特徴的な機能
total の関数本体の定義がふたつあるが、このうち引数の実行時の値と適合する本体が選択され呼び出される。上の本体定義では、引数が空のリストであるときのみ適合し、呼び出される。下の本体定義では、引数が少なくともひとつの要素を持つとき適合し、x に先頭の要素が束縛され、xs に残りのリストが束縛される。この例の場合はパターンに漏れはないが、もし適合するパターンが見つからない場合はエラーになる。
複数の返り値を扱うのもタプルなどを利用して極めて簡明に書くことができる。
このとき、定義される変数は x および y で、それぞれ x は 10 に、y は 20 に定義される。
Haskell で順序付けられた複数の値を扱うのにもっとも柔軟で簡潔な方法はリストを用いることである。次は四季の名前のリストである。
次は初項10、公差4の等差数列のリストである。このリストは無限リストであり、その長さは無限大である。
次の式は先ほどの数列の先頭20項を要素に持つリストである。take n l はリスト l の先頭 n 個の項を要素に持つリストを返す関数である。
Haskell 特徴的な機能
もし正格な動作を持つ言語でこのような定義をしようとすると関数 take に値を渡す前に無限リストを生成することになるが、長さが無限のため無限リストの生成が終わることはなく関数 take がいつまでも呼び出されなくなってしまう。Haskell は遅延評価されるため、このようなリストを定義しても必要になるまで必要な項の値の生成は遅延される。このように無限リストを扱えるのは Haskell の大きな強みである。次は素数列をリスト内包表記を用いて定義した一例である。
リストはその柔軟性から再帰的な関数での値の受け渡しに向いているが、任意の位置の要素にアクセスするためには参照を先頭からたどる必要があるのでランダムアクセスが遅い、要素を変更するたびにリストの一部を作り直さなければならないなどの欠点がある。このため Haskell にも配列が用意されており、高速な参照や更新が必要なプログラムではリストの代わりに配列を用いることでパフォーマンスを改善できる可能性がある。
Haskell 特徴的な機能
型クラスは相異なるデータ型に共通したインターフェイスを持つ関数を定義する。例えば、順序づけることができる要素をもつリストをソートできる関数 sort を定義することを考える。リストの要素のデータ型は関数 sort を定義するときには不明であり、その要素をどのように順序付けるかを予め決定しておくことはできない。数値型も文字列型もそれぞれのデータを順序付けることができるであろうが、共通してデータの順序を返す抽象的な関数 order を定義することができれば、それを用いてソートすることができる。
まず型クラス Comparer を定義して、順序付ける関数 order の形式を定義する。値の順序を調べる関数 order x y は x → y が昇順のときは負の値、降順の時は正の値、x と y が等しいときは 0 を返すものとする。ここで class は型クラスの宣言であることを示す予約語である。
Haskell 特徴的な機能
型クラスを実装するには、対象のデータ型に対してインスタンス宣言を行う。次は型 a の型クラス Comparer に対するインスタンスを宣言したものである。このインスタンス宣言により、Enum のインスタンスである任意の型のリストを辞書順に比較できる。例えば、文字列 Char は Enum のインスタンスの Char のリストであり、このインスタンス定義により order を適用することができるようになる。ここで関数 fromEnum c は文字 c を数値に変換する関数である。Comparer のインスタンスを定義する型 a を Eq および Enum のインスタンスを持つものに限定しているので（(Eq a, Enum a) => の部分）、インスタンス定義の内部で Eq の関数である (/=) や Enum の関数である fromEnum を使うことができている。
次にリストをクイックソートする関数 sort を示す。型クラスを用いて順序付ける関数 order を抽象化したため、このように型クラス Comparer のインスタンスを持つ全ての型の値に適用できる一般化されたソート関数を定義できるのである。
この関数 sort は次のように使う。
Haskell のインスタンス宣言は複数の型に共通する操作を定義するという点で Java や C# の「インターフェイス」と似ているが、Haskell では既存の任意の型についてもインスタンスを定義できる点でもインターフェイスに比べて柔軟である。
すべての式が参照透過である Haskell においては、副作用を式の評価そのものでは表現できない。そのため、Haskell では圏論のアイデアを利用したモナドによって入出力が表現されており、Haskell でも最も特徴的な部分となっている。次は Haskell による Hello world の一例である。実際に単独で実行可能形式にコンパイルできる、小さいが完全なプログラムの一例にもなっている。
Haskell は純粋関数型言語であり、main もやはり参照透過である（副作用はない）。しかし処理系は main として定義された IO () 型の値をそのプログラムの動作を示す値として特別に扱う。putStrLn は標準出力に文字列を出力する動作を表す IO () 型の値を返す関数であり、実行すると引数として渡された Hello,World! を出力する。次に標準入力から一行読み込み、そのまま標準出力に出力するエコープログラムを考える。次のような、C言語などのような表記はできない。getLine 関数は標準入力から一行読み取る関数である。
getLine と putStrLn はそれぞれ次のような型を持っている。
純粋関数型である Haskell では getLine もやはり副作用はなく、getLine は一行読み込むという動作を表す値を常に返す。このように入出力の動作を表す値をアクションと呼ぶ。getLine が返すのは String そのものではなくあくまで IO String という型を持ったアクションであって、それを putStrLn の引数に与えることはできない。正しいエコープログラムの一例は次のようになる。
ここでは演算子 >>= によってふたつのアクションを連結している。このとき、main は一行読み込みそれを出力するというアクションとなり、このプログラムを実行すると処理系は main が持つアクションの内容を実行する。このアクションを実行すると、getLine は一行読み込み、それを putStrLn に渡す。このとき、読み込まれたデータにこれらのアクションの外側からアクセスすることはできない。このため、この式は参照透過性を保つことができる。
モナドは、Freeモナド、Operationalモナドと呼ばれる構造により、より単純なデータ型から導出することもできる。これにより、非常に強力な依存性の注入が実現できる。
Haskell 実例
以下の単純な例は関数型言語としての構文の実例にしばしば用いられるもので、Haskell で示された階乗関数である。
階乗を単一の条件による終端を伴う再帰的関数として表現している。これは数学の教科書でみられる階乗の表現に似ている。Haskell コードの大半は、その簡潔さと構文において基本的な数学的記法と似通っている。
この階乗関数の1行目は関数の型を示すもので、省略可能である。これは「関数 fac は Integer から Integer へ（Integer -> Integer）の型を持つ（::）」と読める。これは整数を引数としてとり、別の整数を返す。もしプログラマが型注釈を与えない場合、この定義の型は自動的に推測される。
2行目では Haskell の重要な機能であるパターンマッチングに頼っている。関数の引数が 0であれば、これは 1 を返す。その他の場合は3行目が試される。これは再帰的な呼び出しで、nが0に達するまで繰り返し関数が実行される。
Haskell 実例
ガードは階乗が定義されない負の値から3行目を保護している。このガードが無ければこの関数は0の終端条件に達することなく、再帰してすべての負の値を経由してしまう。実際、このパターンマッチングは完全ではない。もし関数facに負の整数が引数として渡されると、このプログラムは実行時エラーとともに落ちるであろう。fac _ = error "negative value"のように定義を追加すれば適切なエラーメッセージを出力することができる。
引数 f を伴う高階関数で表現された単純な逆ポーランド記法評価器が、パターンマッチングと型クラス Read を用いた where 節で定義されている。
空リストを初期状態とし、f を使って一語ずつ文字列を解釈していく。f は、注目している語が演算子ならばその演算を実行し、それ以外ならば浮動小数点として計算スタックに積んでいる。
次はフィボナッチ数列のリストである。ある値nに対するfib(n)は一回しか計算しないようになっており、その点ではナイーブなフィボナッチと異なる効率の良いコードとなっている。
無限リストは 余再帰（リストの後ろの値は要求があったときに 0 と 1 の二つの初期要素から開始され算出される）によって実現される。このような定義は遅延評価の実例で、Haskell プログラミングでも重要な部分である。
Haskell 実例
ただし、フィボナッチ数列の生成の場合は、ある要素の値が必要であれば、その要素より前にある要素の値は全て必要である。従って、遅延させた上で結局は後から全てその値を求めることになり、むしろ無駄であるので、この場合は遅延させない組込関数seqを使用したほうが効率は良くなり、fib 1000000 といったような値を計算するような場合には差が見えてくる。あるいはリストの先に出る値から順番に計算させるとそのほうが速い、といったことが起きる。（さらに、フィボナッチ数はnに対して2nと大きな値になるので、そのようなBigIntegerの加算のコストも掛かり、以前にこの場所に書かれていたような「線形時間でのフィボナッチ数列の生成」は、大きい値では不可能である）
どのように評価が進行するかの例示のために、次は6つの要素の計算の後の fibs と tail fibs の値と、どのようにzipWith (+) が4つの要素を生成し、次の値を生成し続けるかを図示したものである。
Haskell 実例
次はGHCで使える言語拡張で、リスト内包表記を並列的な生成を記述できるよう拡張するParallelListCompを用いて書いた同様の式である。（GHCの拡張は特別なコマンドラインフラグ、またはLANGUAGEプラグマによって有効にしなければならない。詳しくはGHCのマニュアルを参照のこと）
先に見た階乗の定義は、次のように関数の列を内包表記で生成して書く事もできる。
特に簡潔に書ける例として、ハミング数が順番に並ぶリストを返す以下のような関数がある。
上に示されたさまざまな fibs の定義のように、これはオンデマンドに数のリストを実現するために無限リストを使っており、1 という先頭要素から後続の要素を生成している。
ここでは、後続要素の構築関数は where 節内の記号 # で表現された中置演算子で定義されている。
各|は、等号の前半の条件部分と、後半の定義部分からなるガード節を構成する。
Haskell ライブラリ
parsec は Haskell で書かれたパーサコンビネータである。パーサの一種であるがコンパイラコンパイラとは異なり、Parsec はパーサのソースコードを出力するのではなく、純粋に Haskell の関数としてパーサを構成する。yacc のようにプログラミング言語と異なる言語を新たに習得する必要がなく、高速でかつ堅牢で、型安全で、演算子の結合性や優先順位を考慮したパーサを自動的に構成したり、動的にパーサを変更することすらできる。
派生として、大幅に高速なパースが可能なattoparsec、高機能でより洗練されたtrifectaがある。
Template Haskell は Haskell のメタプログラミングを可能にする拡張である。Haskell ソースコードの構文木を直接 Haskell から操作することができ、C、C++ のマクロやテンプレートを上回る極めて柔軟なプログラミングを行うことができる。
Haskell ライブラリ
QuickCheck はデータ駆動型のテストを行うモジュールである。自動的にテストデータを作成してプログラムの正当性をテストすることができる。
lensはアクセサの概念を一般化するライブラリであり、様々なデータ構造に対して共通のインタフェースを与える。Getter、Setterは一つの関数として表現されており、それらを合成することもできる。JSONやXMLや、JSONやXML以外の処理にも応用できる。
Haskell 批判
Haskell は他のプログラミング言語には見られない多くの先進的機能を持っているが、これらの機能のいくつかは言語を複雑にしすぎており、理解が困難であると批判されてきた。とりわけ、関数型プログラミング言語と主流でないプログラミング言語に対する批判は Haskell にもあてはまる。加えて、Haskell の潔癖さとその理論中心の起源に起因する不満がある。
2002年に Jan-Willem Maessen、2003年にサイモン・ペイトン・ジョーンズが遅延評価に関連するこの問題を議論し、その上でこの理論的動機を認識した。彼らは実行時のオーバーヘッドの悪化に加え、遅延はコードのパフォーマンスの推察をより困難にすると言及した。
2003年に Bastiaan Heeren と Daan Leijen、Arjan van IJzendoorn は Haskell の学習者にとってのつまづきに気がついた。これを解決するために、彼らは Helium と呼ばれる新たなインタプリタを開発し、この中でいくつかの型クラスのサポートを取り除き、Haskell の機能の一般化を制限することによってエラーメッセージのユーザ親和性を改善した。
Haskell 実装
以下は Haskell 98 仕様を完全に満たす、または仕様に非常に近く、オープンソースライセンスの下で配布されているものである。ここには現在のところ商用のHaskell実装は含まれない。
Glasgow Haskell Compiler
The Glasgow Haskell Compiler は異なる複数のアーキテクチャのネイティブコードにコンパイルできるほか、C言語にコンパイルすることもできる。おそらくGHCは最も知られた Haskell コンパイラで、現在のところGHCのみで動く言語拡張が実装されており、かなり便利ないくつかのライブラリはGHCのみで動作する（たとえば OpenGL のバインディングなど）。
Gofer
初期（Haskell 1.2）の仕様をベースとした、等式推論に向いた方言およびインタプリタの実装。当時の Haskell より Miranda に似た構文、標準の機能をいくつか満たさない、逆に標準にないいくつかの機能の追加、などの特徴があった。マーク・ジョーンズにより開発された。その役割の多くは Hugs に譲られた。Hugs の「g」は Gofer に由来する。
HBC
これは別のネイティブコード Haskell コンパイラ。これはしばらくの間開発が活発ではなくなっているが、未だに利用可能である。
Haskell 実装
Helium
これは新しい Haskell の方言である。開発の際の焦点は、明瞭なエラーメッセージを提供し学習を容易にすることである。Heliumは型クラスをサポートせず、多くのHaskellプログラムとは互換性のない実装である。
Hugs
これはバイトコードインタプリタである。これは速いプログラム編集とそれなりの実行スピードを提供する。これは単純なグラフィックスライブラリを含む。多くの人が Haskell の基本を学ぶのによいが、これはオモチャ的な実装であるということではない。これは最も可搬で軽量な Haskell 実装である。
jhc
これは新しいプログラム変換の研究用としてのみならず、スピードと生成されるプログラムの効率を重視した John Meacham によって書かれた Haskell コンパイラである。
nhc98
これは別のバイトコードコンパイラであるが、そのバイトコードは Hugs より顕著に速く走る。Nhc98は省メモリ使用に焦点を絞っており、古いマシンや遅いマシンにはとりわけよい選択肢となる。
yhc
これはnhc98の派生物で、単純かつ可搬で効率的、integrating Hat のサポートを目標とする。
アタリショック
アタリショック（英語: Video game crash of 1983）とは、アメリカ合衆国における1982年の年末商戦を発端とする、北米ビデオゲーム産業の市場崩壊である。これはアタリを含む各社が発売したゲーム機によって遊ぶことができる、低品質のゲームの供給過多などを要因として引き起こされ、1985年10月に任天堂からNintendo Entertainment System（NES）が発売されるまで続いた。
アタリショック 概要
北米における家庭用ゲームの売上高は、1982年の時点で約32億ドル（同年末の日本円で約7520億円）に達していたが、1985年には1億ドル（同年末の日本円で約200億円）にまで減少した。北米の家庭用ゲーム市場は崩壊し、ゲーム機やホビーパソコンを販売していた大手メーカーのいくつかが破産に追い込まれた。ゲーム市場最大手であったアタリ社も崩壊、分割された。
その背景について、1983年に当時の任天堂社長山内博は講演会で「新型ゲーム機の出現によるAtari 2600の陳腐化、アーケード・ゲームの劣化移植、サード・パーティーが大量に駄作を投入したことから、消費者がゲーム機に失望、新しいカートリッジを買う意欲を失ったため」と語っている。また、1984年にはファミコンのサードパーティーに対して、米国ゲーム市場の教訓から「粗悪なソフトが氾濫しないように任天堂の承認を受けたものだけを作るように注文している 」と経済誌のインタビューに答えている。
アタリショック 概要
また、山内は1986年にも海外紙において、「サードパーティーによる低品質ゲームソフト（俗に言う「クソゲー」）の乱発がアタリの市場崩壊を招いた」という趣旨でその原因に対する自身の認識を述べている。これは後世まで業界の共通認識となっており、2010年当時の任天堂社長である岩田聡は、「粗悪なソフトが粗製濫造されたことで、お客さんからの信頼を失ってしまった」と定義している。ここから転じて、ハードやジャンルに関わらずゲームソフトの供給過剰や粗製濫造により、ユーザーがゲームに対する興味を急速に失い、市場需要および市場規模が急激に縮退する現象を「アタリショックの再来」または単に「アタリショック」と呼ぶこともある。
日本では1996年にNHKで放送された『新・電子立国』で取り上げられて広く知られるようになった。ただし、番組で述べられたように1982年のクリスマス商戦でいきなり市場が崩壊したわけではなく、以下に示すように1982年から1985年にかけて複雑な経過をたどった。
また、アタリショック後に売れ残った大量の不良在庫を埋葬したとされる「ビデオゲームの墓場」が存在するという都市伝説があったが、これは2014年に真実であったことが証明された。
アタリショック 事象
1977年にアメリカでアタリ社から発売されたテレビゲーム機「Atari 2600（発売当初はVideo Computer Systemと呼ばれた。以下、一般略称のVCSと表記）」は、それまでゲーム機のハードウェア本体に内蔵されていたゲームソフトのプログラムROMを、カートリッジに収めて外部から供給できるようにしたことで人気を博した。しかし、同ゲーム機のブームは、発売開始から5年ほどで終わる。
以下に、VCSとその関連商品の市場が辿った状況を、順を追って示す。
アタリ社は、外部からソフトウェアを入れ替えられるAtari VCSを1977年に発売。当初はさっぱり売れなかったが、1980年よりキラーソフトとして、『スペースインベーダー』、『パックマン』、『バトルゾーン』などの人気ゲームが、アーケードゲームから数多く移植され、人気に火が付いた。
アタリ社の上層部と対立して独立したゲーム製作者たちが興したアクティビジョン社が1979年に設立され、家庭用ゲーム史上初のサードパーティとしてVCS用のソフトをリリースした。アタリは当初サードパーティを認めず、アクティビジョンに対して販売差し止めの裁判を起こしたが、ロイヤリティを支払うことで1982年に和解。サードパーティ製ソフトの制作が合法であると認められ、それをきっかけに多数のサードパーティーメーカーが参入した。
アタリショック 事象
これにより売り上げはさらに急加速、アタリに対してロイヤリティさえ払えば基本的に何処の誰でも・自由に・アタリ社に関係なく、同機で動作するソフトウェアを開発し、販売する事が可能になった。このため、市場には様々なゲームソフトが流通し、様々なゲームメーカーが勃興、多くの人に楽しまれるゲームソフトを発売していったのである。それらゲームソフトを動作させるためのゲーム機本体の出荷台数は最終的に1400万台を超えた。
当時VCSをはじめ、各ハードのプログラム仕様などは公開されていなかったが、各サードパーティはファーストパーティから開発者を引き抜いたり、リバースエンジニアリングなどをしてゲームを開発していた。アタリ自身も競合ゲーム機であるマテル・インテレビジョンの開発者を引き抜いて雇用していたほどである（そのためマテルから産業スパイの疑いで訴えられた）。
アタリショック 事象
しかし1982年頃より、家庭用ゲーム市場の急激な拡大に釣られて、ゲームを作ったこともない他業種のメーカーがVCSのサードパーティとして参入した。それらのメーカーの雇った開発者は、アタリやアクティビジョンなどの開発者とは違ってまともにゲームを作る能力がないことから、非常に質の低いソフトまでもが市場に溢れ返った。極端な例として、VCSに参入したクエーカーオーツ（朝食シリアルのメーカー）やピュリナ（ペットフードのメーカー）などが知られる。それらのメーカーは低品質ゲームソフトに大きな宣伝を打ち、家庭用ゲーム市場全体の信用を損なわせた。
この当時、アタリ社は発売されているゲームの内容は一切把握していなかった。また、ユーザーサイドに立ったゲームレビュー雑誌も台頭しておらず、基本的にユーザーは玩具店の店頭で、ゲームソフトのパッケージから、中身の質を推察するしかなかった。
こうして、ユーザーは「買って自宅のVCSに挿し込むまで、本当に面白いかどうか判らない」ような状況にまでなり、ユーザーの購買意欲減退を招いた。
アタリショック 事象
この一方で、ゲームを製造・販売していた弱小の製作会社が勃興と衰退を繰り返し、その激しい新陳代謝の中で「開発企業の倒産」・「在庫の捨て値処分」・「市場にそれらが流れて、ゲームソフト定価ラインを崩壊させる」といった現象を多発させる事となった。つまり、倒産流れのソフトが安価に販売されている隣にあって、新作ソフトの販売価格はいかにも高価に映り、ユーザーの買い控えを招いたのである。
それに加えて、アタリ社が発売したビッグタイトルにも大きな失敗作があった。たとえばアーケードの大人気タイトル『パックマン』のVCS移植版は良い出来ではなく、映画『E.T.』を題材としたゲームは非常に評判が悪かった。1982年に発売されたこれらのビッグタイトルはそれなりの売り上げがあったものの、極端な生産過剰であったため、アタリ社にとって大きな損失になっただけでなく、ユーザーの信用を失う結果にもなった。
生産過剰の背景には、1981年10月当時、売上の増大に生産が追いつかないことを問題視していたアタリが、各販売代理店に対し翌年分の一括発注を求めたことがある。代理店は在庫切れを避けるために大量の水増し発注を行い、アタリはそれを鵜呑みにして需要予測を誤ったまま生産を行った。そしていざ1982年になると発注の多くがキャンセルされてしまい、大量の売れ残りを抱える羽目になったのである。
アタリショック 事象
なお、後にアタリショック最大の要因にしてクソゲーの象徴ともされることになる『E.T.』は、アタリショック後の1983年9月に14台のトラックに満載されてニューメキシコ州アラモゴルド市の砂漠に埋められた（ビデオゲームの墓場）、と当時ニューヨーク・タイムズで報道されている。この「ビデオゲームの墓場」はアタリショックとクソゲーの象徴として半ば都市伝説化して後世に語られていたが、2014年4月に当該の地域で「発掘調査」が行われ、実際に『E.T.』が発掘されたことにより実在したことが確認された（詳細については当該項目の記載を参照）。
1983年当時、市場にはAtari 2600（VCS）の他にも、Atari 5200、バリー・マニュファクチャリングのバリー・アストロケード、コレコのコレコビジョン、コレコジェミニ、エマーソンのアルカディア2001、フェアチャイルドセミコンダクターのフェアチャイルド・チャンネルF、マグナボックスのオデッセイ2、マテルのインテレビジョン、ミルトン・ブラッドリーのVectrexなどのゲーム機が存在しており、さらにOdyssey3やAtari 7800と言った次世代機も発表されていた。各ゲーム機はそれぞれが豊富なゲームソフトのライブラリとサードパーティを抱えていたが、ソフトのラインナップを埋め合わせるために粗製の低品質ゲームソフトが乱発され、供給過剰の状態であった。