Haskellの言語機構整理
はじめに
「すごいHaskellたのしく学ぼう!」を読んだ。Haskellは完全に初体験。本の中で紹介されていたHaskellの機能で、印象的だったものを整理しておく。
セクションタイトルの「基本的」「発展的」は自分独自の主観的な分類。それ単体で完結する単純な機能は基本に入れている。一方で自分が初見で理解しづらいと感じ、概念そのものを受け入れるのに時間がかかったものは発展の方に入れている。
基本的な機能
リスト内包表記
[x * 2 | x <- 1..5] > [2, 4, 6, 8, 10]
パターンマッチ
factorial :: Int -> Int factorial 0 = 1 factorial n = n * factorial(n-1)
ガード
factorial :: Int -> Int factorial n | factorial 0 = 1 | factorial n = n * factorial(n-1)
where節
calcBmis :: [(Double, Double)] -> [Double] calcBmis xs = [bmi x h | (x, h) <- xs] where bmi weight height = weight / height ^ 2
let式
4 * (let a = 9 in a + 1) + 2 > 42
let で値を名前に束縛し、in の中の式が評価される。
case式
describeList :: [a] -> String describeList ls = "The list is " ++ case ls of [] -> "empty." [x] -> "a singleton list." xs -> "a longer list."
ラムダ式
map (\(a, b) -> a + b) [(1, 2), (3, 5)] > [3, 8]
型シノニム
type IntMap v = Map Int v -- 以下の定義と同じ type IntMap = Map Int
発展的な機能
関数適用演算子
定義
($) :: (a -> b) -> a -> b f $ x = f x
使い方
sum(filter(>10) (map (*2) [2..10])) -- 以下のように書き換えられる sum $ filter(>10) (map (*2) [2..10]) sum $ filter(>10) $ map (*2) [2..10]
右側の式を左側の関数の引数として、括弧を減らすことができる。
関数合成
定義
(*) :: (b -> c) -> (a -> b) -> a -> c f . g -> \x -> f (g x)
使い方
map (\x -> negate (abs x)) [5, -3, -6] -- 以下のように書き換えられる map (negate . abs) [5, -3, -6]
データ型の定義
data Shape Circle Float Float Float | Rectangle Float Float Float Float deriving(Show) -- データ型のインスタンスを導出 -- レコード構文(フィールドに名前を与える) data Car = { company :: String , model :: String , year :: Int } deriving(Show)
型コンストラクタ
-- aは型引数 data Maybe a = Nothing | Just a
型クラスの定義
- a は型変数 class Eq a where -- 関数の型定義 (==) :: a -> a -> Bool (/=) :: a -> a -> Bool -- 関数のデフォルト実装(必須でない) (==) = not(x /= y) (/=) = not(x /= y)
型変数は対象クラス(今回はEq)のインスタンスになる型。型引数とは別。
インスタンスの定義
instance Eq TrafficLight where Red == Red = True Blue == Blue = True Yellow == Yellow = True _ == _ = False -- インスタンスになるデータ型の定義 data TrafficLight = Red | Blue | Yellow
ここで言葉の整理をしておく。
- 型クラス
- 振る舞いを定義するインターフェース(振る舞い=メソッド)
- インスタンス
- 型クラスの振る舞いを実装したデータ型
- 「データ型Aが型クラスBに属している」=「型Aは型クラスBのインスタンスである」
Functor型クラス
定義
class Functor f where fmap :: (a -> b) -> fa -> fb
使い方
instance Functor Maybe where fmap f (Just x) = Just(f x) fmap f Nothing = Nothing
Applicative型クラス
定義
class (Functor f) => Applicative f where pure :: a -> f a (<*>) :: f(a -> b) -> f a -> f b
使い方
instance Applicative Maybe where pure = Just Nothing <*>_ = Nothing (Just f) <*> something = fmap f something
Monad型クラス
定義
class Monad m where return :: a -> m a (>>=) :: m a -> (a -> m b) -> m b -- 別名: バインド (>>) :: m a -> m b -> m b x >> y = x >>= \_ -> y -- ユーザーがfailを呼ぶことはない fail :: String -> m a fail msg = error msg
使い方
instance Monad Maybe where return x = Just x Nothing >>= f = Nothing Just x >>= f = f x
ここで Functor, Applicative, Monad の整理をしておく。
| 入力 | 出力 | 適用関数 | 実装メソッド | |
|---|---|---|---|---|
| Functor | f a | f b | a -> b | fmap :: (a -> b) -> f a -> fb |
| Applicative | f a | f b | f(a -> b) | pure :: a -> f a (<*>) :: f(a -> b) -> f a -> fb |
| Monad | m a | m b | a -> m b | return :: m -> m a (>>=) :: a -> m b -> m a -> m b |
<$> (fmapと等価な中置演算子)
定義
(<$>) :: (Functor f ) => (a -> b) -> f a -> f b f <$> x = fmap f x
使い方
pure f <*> x <*> y -- 以下のように書き換えられる fmap f x <*> y f <$> x <*> y
do記法
marySue :: Maybe Bool marySue = Just 9 >>= (\x -> Just(x > 8)) -- 以下のように書き換えることができる marySue = do x <- Just 9 Just (x > 8)
参考
- すごいHaskellたのしく学ぼう!
- 動作環境などはこちらを参考にした記事
- モナドのイメージ的な理解の助けになった記事