Fmap 与 map 区别的示例?

Example of an Fmap to distinguish from map?

我的理解是map和fmap的区别在于后者可以return一个函数?

我正在研究这个 http://learnyouahaskell.com 的仿函数部分,有些解释有点不清楚。

Map 和 fmap 在以下方面的行为相同:

let exMap = map (+1) [1..5]
let exFMap = fmap (+1) [1..5]

fmap returning 函数的一个很好的例子是什么?

不,区别在于fmap适用于任何函子。例如:

readLine :: IO String           -- read a line
fmap length readLine :: IO Int  -- read a line and count its length

Just 4 :: Maybe Int
fmap (+10) (Just 4) :: Maybe Int  -- apply (+10) underneath Just
                                  -- returns (Just 14)

mapa -> b变成一个函数[] a -> [] b(通常写成[a] -> [b])。

fmapa -> b 变成函数 f a -> f b 用于任何函子 f,而不仅仅是 f = []。上面的例子选择了 f = IOf = Maybe.

查看每个函数的类型签名会有所帮助,让我们从您正在查看的 map 函数开始:

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

如您所见,此 map 函数对列表进行操作。然而从逻辑上讲,有许多数据结构可以被映射。以下是一些其他可能的地图:

map :: (a -> b) -> Map k a -> Map k b
map :: (a -> b) -> Maybe a -> Maybe b
map :: (a -> b) -> IO a -> IO b

这只是冰山一角,很多东西都可以映射!

在不支持类型 类 的语言中,这可能就是您所知道的世界。只是有很多 map 函数,您必须使用适当的模块类型来限定它们,以区分您实际指的是哪个 map。在 Haskell!

中并非如此

现在让我们看看fmap:

fmap :: Functor f => (a -> b) -> f a -> f b

此函数的形式与上面所示的完全相同,但适用于任何函子。

仿函数定义如下:

class  Functor f  where
    fmap        :: (a -> b) -> f a -> f b
    (<$)        :: a -> f b -> f a
    (<$)        =  fmap . const

希望这能让人明白仿函数只是 支持映射的东西。

因此fmap是一般的,而map是具体的。

fmapmap 更通用 - 事实上对于列表来说没有区别 - 这里你有 map == fmap.

让我们从fmap

的定义开始
class Functor f where
    fmap :: (a -> b) -> (f a -> f b)

这实际上是说您可以将一个简单的函数转换为将容器转换为形状相同但元素不同的容器的函数。

instance Functor [] where
   fmap = map

instance Functor Maybe where
   fmap _ Nothing = Nothing
   fmap f (Just something) = Just (f something)

还有很多,我想几乎每个只有一个类型参数的容器都可以是一个仿函数

作为练习,您可以尝试为

定义一个实例
data Tree a = Tree a [a]

fmap的用法见@chi的回答