プログラミングと日々思ったことなど

ブログ名通りです。仕事でプログラミングをはじめました。

Haskell【Functor型問題と復習】

型宣言
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の実装ができる)と書いてある記事もあるので、読み終わったらもう一度考える。