【Haskell】入門ガイド - 純粋関数型言語の特徴・書き方・開発環境を徹底解説
Haskell は純粋関数型プログラミング言語です。1990年に学術研究から生まれ、現在も実用・研究の両面で使われています。
この記事では、Haskell の特徴、他言語との違い、基本的な書き方、開発環境の構築方法、実務での活用場面までを解説します。
Haskell の概要
| 項目 | 内容 |
|---|---|
| 作者 | Haskell委員会(学術コミュニティ) |
| 初版 | 1990年 |
| パラダイム | 純粋関数型 |
| 型システム | 静的・強い型付け |
| 評価戦略 | 遅延評価 |
| 公式サイト | haskell.org |
Haskell の主な特徴
1. 純粋関数型
同じ入力に対して常に同じ出力を返します。変数の再代入は不可能で、「どこかで値が変わった」というバグが原理的に起きません。
2. 強力な型システム
コンパイル時に型エラーを検出します。型推論があるため、すべての型を手動で書く必要はありません。
- 代数的データ型: 列挙型、フィールド付き型、再帰的な型を定義できる
- 型クラス: Javaのインターフェースに似た仕組み
3. 遅延評価(Lazy Evaluation)
値は必要になるまで計算されません。無限リストも扱えます。
-- 無限リストを定義しても問題ない
naturals = [1..]
-- 先頭10個だけ取得する
take 10 naturals -- [1,2,3,4,5,6,7,8,9,10]
4. パターンマッチング
データの構造に応じた場合分けを簡潔に書けます。
-- リストの長さを求める関数
myLength :: [a] -> Int
myLength [] = 0 -- 空リストなら0
myLength (_:xs) = 1 + myLength xs -- 先頭を除いた残りの長さ + 1
5. モナド(Monad)
副作用(入出力、エラー処理など)を純粋な関数型の枠組みで扱う仕組みです。IO型、Maybe型、do記法で使用します。
6. 参照透過性
式をその結果で置き換えてもプログラムの動作が変わりません。リファクタリングが安全に行えます。
他の言語との比較
| 特徴 | Haskell | TypeScript | Python |
|---|---|---|---|
| パラダイム | 純粋関数型 | マルチパラダイム | マルチパラダイム |
| 型システム | 静的・強い | 静的・構造的 | 動的 |
| 評価戦略 | 遅延評価 | 正格評価 | 正格評価 |
| 副作用 | モナドで管理 | 自由 | 自由 |
| 学習コスト | 高い | 中程度 | 低い |
| エコシステム | 限定的 | 非常に大きい | 非常に大きい |
Rust、Scala、TypeScript、Swiftなど、多くのモダン言語にHaskellのアイデア(型推論、パターンマッチング、Option型など)が取り入れられています。
メリットとデメリット
バグが少ない、リファクタリングが安全、並行処理と相性が良い、コードが簡潔、高い抽象化能力
学習曲線が急、ライブラリが少ない、遅延評価のメモリ挙動が予測しにくい、エラーメッセージが分かりにくい場合がある、採用実績が限定的
基本的な書き方
関数定義
-- 型シグネチャ(推奨)
double :: Int -> Int
double x = x * 2
-- 使い方
double 5 -- 10
変数(束縛)
-- let式
circleArea r =
let pi = 3.14159
in pi * r * r
-- where句
circleArea' r = pi * r * r
where pi = 3.14159
条件分岐
-- if式(必ず値を返す)
abs' x = if x >= 0 then x else -x
-- ガード
bmi :: Double -> String
bmi x
| x < 18.5 = "やせ型"
| x < 25.0 = "標準"
| otherwise = "肥満"
-- パターンマッチ
greet :: String -> String
greet "Alice" = "こんにちは、Alice!"
greet "Bob" = "やあ、Bob!"
greet name = "はじめまして、" ++ name ++ "さん"
リスト操作
-- リストの作成
nums = [1, 2, 3, 4, 5]
range = [1..10] -- [1,2,3,4,5,6,7,8,9,10]
evens = [2,4..20] -- [2,4,6,8,10,12,14,16,18,20]
-- 基本操作
head [1,2,3] -- 1
tail [1,2,3] -- [2,3]
length [1,2,3] -- 3
reverse [1,2,3] -- [3,2,1]
-- map / filter
map (* 2) [1,2,3] -- [2,4,6]
filter even [1,2,3,4,5] -- [2,4]
-- リスト内包表記
[x * 2 | x <- [1..5], even x] -- [4,8]
自分の型を作る
-- 列挙型
data Season = Spring | Summer | Autumn | Winter
-- レコード型
data Person = Person
{ name :: String
, age :: Int
}
IO(入出力)
main :: IO ()
main = do
putStrLn "名前を入力してください:"
name <- getLine
putStrLn ("こんにちは、" ++ name ++ "さん!")
関数型の特徴がわかる例
高階関数
関数を引数として渡せます。
-- 価格リストに消費税を適用
prices = [100, 250, 80, 340]
withTax = map (* 1.1) prices -- [110.0, 275.0, 88.0, 374.0]
関数合成
小さな関数を . 演算子で組み合わせます。
-- 偶数だけ2倍にして合計する
process :: [Int] -> Int
process = sum . map (* 2) . filter even
process [1, 2, 3, 4, 5] -- 12 (2*2 + 4*2 = 12)
部分適用
add :: Int -> Int -> Int
add x y = x + y
add10 :: Int -> Int
add10 = add 10 -- 「10を足す関数」が生まれる
add10 5 -- 15
add10 20 -- 30
畳み込み(fold)
foldl で多くの処理を汎用的に書けます。
-- sumをfoldlで実装
mySum = foldl (+) 0
mySum [1,2,3,4,5] -- 15
-- 文字列結合
myJoin sep = foldl1 (\acc x -> acc ++ sep ++ x)
myJoin ", " ["a","b","c"] -- "a, b, c"
実用例: 合格者の名前一覧
students = [("Alice", 85), ("Bob", 60), ("Charlie", 92), ("Diana", 45)]
passedNames :: [(String, Int)] -> [String]
passedNames = map fst . filter (\(_, score) -> score >= 70)
passedNames students -- ["Alice", "Charlie"]
関数型では「何を取り出すか」の定義だけを書きます。ループや一時変数は登場しません。
開発環境の構築
Haskell のツールチェーン管理ツールをインストールします。
Windows(PowerShell):
Set-ExecutionPolicy Bypass -Scope Process -Force
[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072
Invoke-WebRequest https://www.haskell.org/ghcup/sh/bootstrap-haskell.ps1 -OutFile bootstrap-haskell.ps1
./bootstrap-haskell.ps1macOS / Linux:
curl --proto '=https' --tlsv1.2 -sSf https://get-ghcup.haskell.org | sh GHCup により以下がインストールされます。
| ツール | 役割 |
|---|---|
| GHC | Haskell コンパイラ |
| Cabal | パッケージ管理・ビルドツール |
| Stack | 代替のビルドツール |
| HLS | 言語サーバー(エディタ連携) |
VS Code に Haskell 拡張機能をインストールするだけで、以下が有効になります。
- コード補完
- エラー表示
- 定義ジャンプ
- 型情報の表示
# プロジェクトを作成
cabal init --interactive
# ビルドと実行
cabal build
cabal run
# 対話環境(GHCi)
cabal repl
# 単一ファイルの実行
runghc Main.hs GHCi(対話環境)の主なコマンド
| コマンド | 説明 |
|---|---|
:load Main.hs | ファイルを読み込む |
:reload | 再読み込み |
:type expr | 式の型を表示 |
:info name | 情報を表示 |
:quit | 終了 |
パッケージの追加
.cabal ファイルの build-depends にパッケージ名を追加します。パッケージは Hackage で検索できます。
Haskell が選ばれる場面
特に向いている領域
| 領域 | 理由 | 実例 |
|---|---|---|
| コンパイラ・言語処理系 | AST操作に最適 | GHC、PureScriptコンパイラ |
| 金融・フィンテック | 正確性が求められる | Standard Chartered、Cardano |
| CLIツール | 型安全な引数処理 | pandoc、ShellCheck、hadolint |
| パーサー・データ変換 | パーサーコンビネータが強力 | parsecライブラリ |
| 形式検証・静的解析 | 数学的基盤との親和性 | 各種解析ツール |
選定の判断基準
正確性が最優先、複雑なビジネスロジック、並行・並列処理、長期保守するコード、DSLの構築
チームに経験者がいない、素早いプロトタイピングが必要、モバイル/GUIアプリ、既存システムとの統合が多い
Web開発での活用
Haskell を使うならどの部分か
効果が高い部分
- 計算・変換ロジック(APIとして切り出す): 料金計算、データ変換、ルール判定
- バッチ処理・データパイプライン: ログ集計、レポート生成、データクレンジング
- CLI ツール・社内ツール: コード生成、設定ファイルバリデーター
使わない方がいい部分
- フロントエンド
- REST API の CRUD
- 認証・セッション管理
- ファイルアップロード
- リアルタイム通信
「Webアプリの一部」ではなく「Webアプリの裏側にある独立した計算処理」として使うのが最も現実的です。
代替手段も検討する
多くの場合、TypeScript(strictモード)、Rust、Scala、F# で十分なことがあります。特に TypeScript はフロントエンドと型を共有できるため、Web では総合的なメリットが大きいです。
初心者におすすめの学習ステップ
| ステップ | 制作物 | 学べること | 目安期間 |
|---|---|---|---|
| 1 | 電卓・FizzBuzz | パターンマッチング、再帰、ガード構文 | 1〜2日 |
| 2 | Todoリスト(CLI) | ファイルIO、リスト操作、ユーザー入力 | 3〜5日 |
| 3 | じゃんけんゲーム | ランダム処理、代数的データ型 | 2〜3日 |
| 4 | JSONパーサー | パーサーコンビネータ、再帰的データ型 | 1〜2週間 |
| 5 | 簡易インタプリタ | Haskellの真骨頂、AST操作 | 2〜4週間 |
- 小さく始める まずは電卓やFizzBuzzから
- GHCi活用 対話環境で試しながら学ぶ
- 型を先に書く 型シグネチャから考える習慣をつける
- エラーを読む GHCのエラーメッセージは情報量が多い
参考文献
- Haskell 公式サイト
- Learn You a Haskell for Great Good!
- Hackage - Haskell パッケージリポジトリ
- GHCup - Haskell ツールチェーンインストーラー
まとめ
Haskell は純粋関数型プログラミング言語で、強力な型システム、遅延評価、モナドによる副作用管理が特徴です。
- コンパイラ開発、金融、CLIツールなど正確性が求められる場面で強みを発揮する
- 学習曲線は急だが、関数型の考え方を深く学べる
- Web開発では計算エンジンやバッチ処理として部分的に活用するのが現実的
- Rust、TypeScript、Scalaなど多くのモダン言語にアイデアが取り入れられており、学ぶ価値は他の言語にも波及する
- 実務で「全部 Haskell」は少ないが、関数型の考え方を身につけて他の言語に活かすアプローチが有効