型宣言
fmap :: (a -> b) -> Map k a -> Map k b
main :: IO ()
型宣言には定義の型を明示する役割があり、定義が自明である(main :: IO()とか)場合は、これを省略することができる。
定義
main = putStrLn "Hello, Haskell world!"
型クラス
型の振る舞いを定義するもの。
オブジェクト指向におけるクラスとは概念が異なり、Interfaceや抽象クラスに相当。
class Eq a where
(==) :: a -> a -> Bool
(/=) :: a -> a -> Bool
x == y = not (x /= y)
x /= y = not (x == y)
Eqという名の新しい型クラスの定義。aは型変数で、将来Eqのインスタンスとなるであろう型を表す。
インスタンス
型クラスの制約を満たすように定義した型。
オブジェクト指向におけるインスタンス(クラスの実体)とは概念が異なり、クラスの実装(Implement)に相当。
新しい型クラスを定義するのがclassで、型を型クラスのインスタンスにするのがインスタンス。
instance Eq TrafficLight where
Red == Red = True
Functor型クラスの型宣言
class Functor f where
fmap :: (a -> b) -> f a -> f b
Functorの持ってるfmap?
fmapは a -> b を Map k a -> Map k b という関数に変換する関数。
練習問題
Map k がどのようにFunctorのインスタンスになるのか
Map(Data.Map)の関数の型宣言
Map.fromList :: (Ord k) => [(k, v)] -> Map.Map k v
Map.lookup :: (Ord k) => k -> Map.Map k a -> Maybe a
Map.insert :: Ord k => k -> a -> Map.Map k a -> Map.Map k a
有識者の助言
関数(f:: v -> w)を受け取り、任意のMap k v を Map k wに移す関数 fmap を持つ
つまりfmap は全ての値v に対して関数 f を適用し、Mapの値の型を w にするような関数
-- ① import Data.Map as DataMap import Data.List as DataList class MyFunctor f where myfmap :: (a -> b) -> f a -> f b instance (Ord k) => MyFunctor (DataMap.Map k) where myfmap f x = DataMap.fromList $ DataList.map (\(p,q) ->(p,f q)) $ DataMap.toList x -- ② instance Ord k => Functor (Map k) where fmap f = fromList . map (\(k,v) -> (k,f v)) . toList -- ③ class MyFunctor f where myfmap :: (a -> b) -> f a -> f b instance (Ord k) => MyFunctor (DataMap.Map k) where myfmap = DataMap.map main = return ()
MapはHaskellライブラリですでに定義されている(Mapの実装は隠蔽されている=内部構造ので、値を直接触ることはできない)ため、実際にテストすることはできないらしい。
newtypeを使えばできる(代わりに提供される便利関数を使うと、fmapの実装ができる)と書いてある記事もあるので、読み終わったらもう一度考える。