Haskell - Functors

时间:2014-11-29 00:03:50

标签: haskell functor

我正在尝试了解Functors的工作原理,所以我在这里阅读:http://learnyouahaskell.com/making-our-own-types-and-typeclasses#the-functor-typeclass

我有一个函数,它接受一个映射并计算值的总和(这是一个列表)。

reduce :: Map String [Int] -> Map String Int
reduce = fmap sum

我真的不明白fmap是如何运作的,所以我读了它并尝试制作我自己的版本。我无法真正测试它,因为Map已在Haskell库中定义。

这是对的吗?

instance Functor (Map k) where  
    fmap f fromList[] = []
    fmap f fromList[(k, v): xs] = (f v) fmap xs

1 个答案:

答案 0 :(得分:7)

你的榜样在道德上是正确的,但它有一些错误。最明显的是,由于fromList ...不是构造函数,因此无法在fromList上进行模式匹配。 Data.Map模块不会导出实际构造函数,因此我们根本不能进行模式匹配 - 这是为了确保您不能访问该模块中使用的内部树表示并可能破坏某些不变量。

更好的例子可以是例如(Ord k需要约束Map,如@gallais提到的那样)

instance Ord k => Functor (Map k) where
   fmap f m = fromList (map modify (toList m))
         where modify (k,v) = (k, fv)

这基本上将整个地图转换为由键值对组成的关联列表,然后更改应用f的每个值,然后重新生成Map。更简洁,它可以写成

instance Ord k => Functor (Map k) where
   fmap f = fromList . map (\(k,v) -> (k,f v)) . toList

请记住,这不是非常有效 - Map模块中的实际实例不必通过中间列表。

最后,请注意您无法定义自己的实例,因为Map模块已经为您提供了一个实例。如果您真的想要试验它,可以声明newtype

newtype MyMap k v = MyMap { unMyMap :: Map k v }

instance Functor (MyMap k) where
   fmap f = MyMap . fromList . map (\(k,v) -> (k,f v)) . toList . unMyMap