fugafuga.write

日々のログ

すごいH本 part53

Tree型 を Functor のインスタンスにする

instance Functor Tree where
    fmap f EmptyTree = EmptyTree
    fmap f (Node x left right) =
        Node (f x) (fmap f left) (fmap f right)

実行する

*Main> fmap (*2) EmptyTree
EmptyTree
*Main> fmap (*4) (foldr treeInsert EmptyTree [5,7,3])
Node 12 EmptyTree (Node 28 (Node 20 EmptyTree EmptyTree) EmptyTree)

Either は Functor かどうか

Functor 型クラスは、型引数を1つだけ取る型コンストラクタを要求している。 Either は型引数を2つとる。

標準ライブラリでは、Either a 型が Functor のインスタンスになっている。

instance Functor (Either a) where
    fmap f (Right x) = Right (f x)
    fmap f (Left x) = Left x

実行

*Main> fmap (*2) (Right 2)
Right 4
*Main> fmap (*2) (Left 2)
Left 2

所感

Functor は箱っぽいものに関数を適用できる。 箱っぽいものとは型がまだ決まってない値を持つことができるもの。 Maybe a や Either a b などの型引数をとるもの。

Map k v を Functor の instance にする練習問題はまた今度やる。

すごいHaskellたのしく学ぼう!

すごいHaskellたのしく学ぼう!

  • 作者: MiranLipovaca
  • 出版社/メーカー: オーム社
  • 発売日: 2017/07/14
  • メディア: Kindle版
  • 購入: 4人 クリック: 9回
  • この商品を含むブログを見る

すごいH本 part52

Functor 型クラス

Functor は全体を写せるものの型クラス

class Functor f where
    fmap :: (a -> b) -> f a -> f b

fmap を持つ。デフォルト実装は無い。fは1つの型引数を取る型コンストラクタ。

fmapは、

  • ある型 a から 別の型 b への関数
  • ある型 a に適用されたファンクター値

を取り、

  • 別の型 b のほうに適用されたファンクター値

を返す。

これは map に似ている

map :: (a -> b) -> [a] -> [b]

リストに対する Functor インスタンス宣言

instance Functor [] where
    fmap = map

map は リスト限定で動作する fmap と同じ。

*Main> fmap (*2) [1..3]
[2,4,6]
*Main> map (*2) [1..3]
[2,4,6]

Maybe は Functor

ファンクターになれるのは、箱のような働きをする型。 リストは色々な値を格納できる箱とみなせる。 Maybe も同じ。

instance Functor Maybe where
    fmap f (Just x) = Just (f x)
    fmap f Nothing = Nothing

Maybe型の値に対して fmap を適用する

*Main> fmap (++ " HEY GUYS IM INSIDE THE JUST") (Just "Something serious.")
Just "Something serious. HEY GUYS IM INSIDE THE JUST"
*Main> fmap (++ " HEY GUYS IM INSIDE THE JUST") Nothing
Nothing
*Main> fmap (*200) (Just 200)
Just 40000
*Main> fmap (*200) Nothing
Nothing

所感

Functor は map インターフェースみたいなものか。"関数を写す"というのがよくわからん。"関数を適用する"と違いがあるのか。

すごいHaskellたのしく学ぼう!

すごいHaskellたのしく学ぼう!

  • 作者: MiranLipovaca
  • 出版社/メーカー: オーム社
  • 発売日: 2017/07/14
  • メディア: Kindle版
  • 購入: 4人 クリック: 9回
  • この商品を含むブログを見る

すごいH本 part51

YesNo 型クラスをつくる

JavaScript 的なゆるふわ真理値の型クラスをつくる

class YesNo a where
    yesno :: a -> Bool

真理値の概念を何らかの形で含むとみなせる型の値を取り、それが true かどうかを返す。

インスタンスを定義する

instance YesNo Int where
    yesno 0 = False
    yesno _ = True

instance YesNo [a] where
    yesno [] = False
    yesno _ = True

instance YesNo Bool where
    yesno = id

instance YesNo (Maybe a) where
    yesno (Just _) = True
    yesno Nothing = False

instance YesNo (Tree a) where
    yesno EmptyTree = False
    yesno _ = True

instance YesNo TrafficLight where
    yesno Red = False
    yesno _ = True

id は引数を一つ取って同じものを返す標準関数。

実行

*Main> yesno $ length []
False
*Main> yesno "haha"
True
*Main> yesno ""
False
*Main> yesno $ Just 0
True
*Main> yesno True
True
*Main> yesno EmptyTree
False
*Main> yesno []
False
*Main> yesno [0,0,0]
True
*Main> :t yesno
yesno :: YesNo a => a -> Bool

if っぽい関数を実装する

yesnoIf :: (YesNo y) => y -> a -> a -> a
yesnoIf yesnoVal yesResult noResult =
        if yesno yesnoVal
            then yesResult
            else noResult

実行

*Main> yesnoIf [] "YES!!" "NO!!"
"NO!!"
*Main> yesnoIf [2,3,4] "YES!!" "NO!!"
"YES!!"
*Main> yesnoIf True "YES!!" "NO!!"
"YES!!"
*Main> yesnoIf (Just 400) "YES!!" "NO!!"
"YES!!"
*Main> yesnoIf Nothing "YES!!" "NO!!"
"NO!!"

所感

型クラスの関数にそのインスタンスを適用すると、型によって実装が違うので振る舞いが変わる。多態性を表現できるようになった。

すごいHaskellたのしく学ぼう!

すごいHaskellたのしく学ぼう!

  • 作者: MiranLipovaca
  • 出版社/メーカー: オーム社
  • 発売日: 2017/07/14
  • メディア: Kindle版
  • 購入: 4人 クリック: 9回
  • この商品を含むブログを見る

すごいH本 part50

祝 part 50

型クラスのサブクラス化

Num クラスの型宣言

class (Eq a) => Num a where
...

Num 型クラスのインスタンスは Eq 型クラスのインスタンスである必要がある。

サブクラス作成に必要な知識はこれだけ。

多相型を型クラスのインスタンスにする

型コンストラクタを持つ Maybe など。

instance Eq (Maybe Int) where
...
instance Eq (Maybe Char) where
...

などと定義していたらキリがない。

なので多相型は型引数を変数として残すことが許可されている。

instance Eq (Maybe m) where
    Just x == Just y = x == y
    Nothing == Nothing = True
    _ == _ = False

Maybe m とすることで具体型として宣言する。 Maybe something のような格好をしている型はまとめてEqのインスタンスにしたい、を表現している。

しかし、Maybe の中身に対して == を使用していることが問題となってくる。 型 m はEq型クラスのインスタンスである保証はどこにもない。 そこで、型制約の出番となる。

instance (Eq m) => Eq (Maybe m) where
    Just x == Just y = x == y
    Nothing == Nothing = True
    _ == _ = False

こうすることで、型 m は Eq 型クラスのインスタンスでなければならないという制約が課される。 これは自動導出がやっていることと同じ。

  • 型クラス宣言で型クラス制約を使うのは、ある型クラスを別の型クラスのサブクラスにする場合。
  • インスタンス宣言で型クラス制約を使うのは、型の中身に対する必要条件を記述する場合。

ghci で:info TypeClass とすると、型の情報が見れる。TypeClass は 型クラス、型、型コンストラクタに使える。

:i でもいける。

*Main> :info Maybe
data Maybe a = Nothing | Just a         -- Defined in ‘GHC.Base’
instance Eq a => Eq (Maybe a) -- Defined in ‘GHC.Base’
instance Monad Maybe -- Defined in ‘GHC.Base’
instance Functor Maybe -- Defined in ‘GHC.Base’
instance Ord a => Ord (Maybe a) -- Defined in ‘GHC.Base’
instance Read a => Read (Maybe a) -- Defined in ‘GHC.Read’
instance Show a => Show (Maybe a) -- Defined in ‘GHC.Show’
instance Applicative Maybe -- Defined in ‘GHC.Base’
instance Foldable Maybe -- Defined in ‘Data.Foldable’
instance Traversable Maybe -- Defined in ‘Data.Traversable’
instance Monoid a => Monoid (Maybe a) -- Defined in ‘GHC.Base’

*Main> :i Char
data Char
  = ghc-prim-0.5.0.0:GHC.Types.C# ghc-prim-0.5.0.0:GHC.Prim.Char#
        -- Defined in ‘ghc-prim-0.5.0.0:GHC.Types’
instance Bounded Char -- Defined in ‘GHC.Enum’
instance Enum Char -- Defined in ‘GHC.Enum’
instance Eq Char -- Defined in ‘ghc-prim-0.5.0.0:GHC.Classes’
instance Ord Char -- Defined in ‘ghc-prim-0.5.0.0:GHC.Classes’
instance Read Char -- Defined in ‘GHC.Read’
instance Show Char -- Defined in ‘GHC.Show’

所感

型クラスとそのインスタンスについて理解が進んだ。型の世界が広い。

すごいHaskellたのしく学ぼう!

すごいHaskellたのしく学ぼう!

  • 作者: MiranLipovaca
  • 出版社/メーカー: オーム社
  • 発売日: 2017/07/14
  • メディア: Kindle版
  • 購入: 4人 クリック: 9回
  • この商品を含むブログを見る