Haskell

プログラミング言語 >>他のプログラミング言語 ■カテゴリ / ■テンプレート Haskell（ハスケル）は非正格な評価を特徴とする純粋関数型プログラミング言語である。名称は数学者であり論理学者であるハスケル・カリーに由来する。 Haskell は高階関数や静的多相型付け、定義可能な演算子、例外処理といった多くの言語で採用されている現代的な機能に加え、パターンマッチングやカリー化、リスト内包表記、ガードといった多くの特徴的な機能を持っている。また、遅延評価や再帰的な関数や代数的データ型もサポートしているほか、独自の概念として圏論のアイデアを利用し参照透過性を壊すことなく副作用のある操作（例えば 代入、入出力、配列など）を実現するモナドを含む。このような機能の組み合わせにより、手続き型プログラミング言語では記述が複雑になるような処理がしばしば簡潔になるばかりではなく、必要に応じて手続き型プログラミングを利用できる。 Haskell は関数型プログラミングの研究対象として人気が高い。あわせて Parallel Haskell と呼ばれるマサチューセッツ工科大学やグラスゴー大学によるものをはじめ、他にも Distributed Haskell や Eden といった分散バージョン、Eager Haskell と呼ばれる投機的実行バージョン、Haskell++ や O'Haskell、Mondrian といったオブジェクト指向バージョンも複数存在しているなど、いくつもの派生形が開発されてきている。 GUI開発向けサポートの新しい方法を提供する、Concurrent Clean と呼ばれる Haskell に似た言語もある。Haskell と Concurrent Clean の最大の違いは、モナドを代用する一意型の採用である。 Haskell は比較的小規模なユーザコミュニティを持つが、その力はいくつかのプロジェクトで十分に生かされてきた。オードリー・タンによる Pugs は Perl6 のインタプリタとコンパイラの実装で、書くのにたったの数ヶ月しかかからなかったなど Haskell の有用性を証明するものである（現在は開発停止）。Darcs はさまざまな革新的な機能を含むリビジョンコントロールシステムである。Linspire Linux は Haskell をシステムツール開発に選択した。 Haskell の急速な進化は今も継続しており、Glasgow Haskell Compiler（GHC）は現在の事実上の標準の処理系であるといえる。 ICFP Programming Contestでは2001、2004、2005、2010、2013、2014、2015、2016年に最優秀賞に選ばれている。 Cabal（英語版） は Haskell 用のビルドおよびパッケージングシステムである。Cabal を利用して Haskell ライブラリのアーカイブである Hackage を参照して、新たなパッケージを簡単にインストールすることもできる。しばしばパッケージの依存地獄（英語版）が発生しがちだが、それらを解決するため、Stack（英語版）という環境も有志によって提供されている。 1985年、遅延関数言語である Miranda がリサーチ・ソフトウェア社によって発表された。1987年にはこのような非正格な純粋関数型プログラミング言語が十二以上存在していたが、そのうち最も広く使われていた Miranda はパブリックドメインではなかった。オレゴン州ポートランドで開催された Functional Programming Languages and Computer Architecture (FPCA '87) において開かれた会議中に、遅延関数型言語のオープンな標準を作成するための委員会が発足されるべき、という強い合意が参加者のあいだで形成された。委員会の目的は、関数型言語のデザインにおける将来の研究のための基礎として役立つ共通のものへと、既存の関数型言語を統合することであった。 最初の版の Haskell（Haskell 1.0）は1990年に作成された。委員会の活動は一連の言語仕様を結果に残し、1997年後半にそのシリーズは、安定しており小さく可搬なバージョンの言語仕様と、学習用および将来の拡張の基礎としての基本ライブラリなどを定義したHaskell 98 に到達した。実験的な機能の付加や統合を通じて Haskell98 の拡張や派生物を作成することを、委員会ははっきりと歓迎した。 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 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 の型名は先頭が大文字でなければならない。標準で存在する単純なデータ型としては、Bool（真偽値）型、Int（整数）型、Float（単精度浮動小数点数）型、Char（文字）型、String（文字列）型などが予め定義されている。任意の式の型を定義するには、式と型の間に :: 記号をおく。また、変数などのシンボルを定義する際に変数名を式に指定して書くことで、その変数の型を指定することができる。例えば、次は円周率およびネイピア数を定数として定義し、さらにその型も浮動小数点型として指定している。 pi :: Float pi = 3.1415926535 e = 2.7182818284 :: Float -- 式の中でその型を指定している 関数の型は、各引数の間を -> 記号で区切って表記する。関数は引数をひとつ適用するたびに、その型は -> で区切られたうちの一番左が消えた型となると考えればよい。例えば、ふたつの整数を引数にとりその最大公約数を返す関数 gcd の型は次のように定義される。 gcd :: Int -> Int -> Int -- 関数名 :: 引数1の型 -> 引数2の型 -> 返り値の型 型変数を使い、型を抽象化することもできる。これは C++ のテンプレートや Java のジェネリクスに相当するが、様々な種(型の型)に適用できるためより柔軟である。例えば、a 型の値をとり、それをそのまま返す恒等関数 id を型の指定とともに定義すると以下のようになる。ここで任意の型を示す型名 a が定義に使われているが、このように先頭が小文字で始まっている型名は具体的な型名ではなく型変数である。この関数はあらゆる型の値を引数にとることができる。 id :: a -> a id x = x また、データ型はパラメータとして型変数を持つことができる。例えば、スタックやハッシュテーブルなどのデータ型は、その要素の型を型変数として定義する。ハッシュテーブルを実装するデータ型 HashMap :: * -> * -> * があり、キーに文字列（String）、値に整数（Int）を持つハッシュテーブル hashtable の型は次のようになる。 hashtable :: HashMap String Int そのほか、特殊な表記を持つ型としてリストとタプル、文字列がある。リストは Haskell で極めて頻繁に用いられるため、特別な構文が用意されている。リストは要素の型を角括弧で囲む。次は Char（文字）のリストを束縛する変数 text の定義である。文字のリストは文字列と等価である。2行目にあるように、文字列は殆どのプログラミング言語と同じように二重引用符で囲む。コメントにHaskellでのリストの表記を添えた。最後にデシュガー（糖衣構文を元の表記に戻すこと）したリストの表記法を示した。textもhelloも等価である。 text :: [Char] text = "Hello" -- ['H','e','l','l','o'] の糖衣構文 hello :: [Char] hello = 'H':'e':'l':'l':'o':[] タプルは要素の型をカンマで区切り、括弧で囲む。次は Float（浮動小数点数）の値をもつ2次元座標のタプルが束縛される変数 point の定義である。 point :: (Float,Float) point = (3, 7) タプルは2以上ならいくつでも要素を持つことができる。1要素のタプルは優先順位の括弧と表記が衝突し、また用途がないので存在しない。要素数がゼロのタプルは特に「ユニット」(Unit) と呼ばれ、有効な値を持たないなどの時に使われる。 type キーワードを用いて、型に別名をつけることができる。次は [Char] に String という別名をつけている。 type String = [Char] text :: String Haskellの型は型構築子（型コンストラクタ、type constructor）から構築される。型構築子Tに型変数（Type variables）v1 v2 vNを与え型式（type expression）T v1 v2 vNとして評価することで型が構築される。型構築子の例には以下が挙げられる。 例えば型構築子Maybeに型変数Intを渡し、Maybe Intとすることで型が構築される。 関数名は先頭が小文字でなければならず、記号を含むことはできない。演算子名は記号のみで構成されていなければならない。関数の定義ではC言語のような引数を囲む括弧や区切りのカンマは使われず、単に引数を空白文字で区切って表記する。次は先程示した恒等関数 id に、型の定義に加えて本体の定義もした例である。 id :: a -> a id x = x -- 関数名 仮引数1 仮引数2 &hellip; = 関数本体の式 関数の適用も同様で、単に関数に続いて空白文字で区切った引数を並べればよい。以下では上記の恒等関数 id を(ここでは使う必要はないが)適用して、別の変数を定義した例である。 hoge = id "piyo" -- hoge == "piyo" となる。 引数がつねに2個であることや引数の間に演算子をおくことなどを除けば、演算子についても関数の定義や適用と同様である。標準で定義されている算術演算子を使って、BMIを計算する関数 bmi を定義してみる。 bmi :: Float -> Float -> Float bmi weight height = weight / height