【问题标题】:Example of an Fmap to distinguish from map?区分地图的 Fmap 示例?
【发布时间】:2016-09-29 08:52:57
【问题描述】:

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

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

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

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

什么是 fmap 返回函数的好例子?

【问题讨论】:

    标签: haskell functor


    【解决方案1】:

    不,区别在于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

    【讨论】:

    • 您能否更进一步,简单地区分仿函数与应用仿函数有何不同?
    • 如果你有a->bf a,当f是函子时,你可以使用fmap得到f b。但是,如果您有f (a->b)f a,则无法获得f b:该函数被包裹在f 之下,并且无法使其与其参数交互。应用函子改为定义一个额外的操作<*> 允许这样做。
    • 一个可用的函子是“阅读器”,它确实与函数有关,但现在可能不是了解它的最佳阶段。
    【解决方案2】:

    查看每个函数的类型签名会有所帮助,让我们从您正在查看的 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
    

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

    Functor 是这样定义的:

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

    希望这表明仿函数只是支持被映射的东西。

    因此fmap 是通用的,而map 是特定的。

    【讨论】:

    • 你应该澄清你不能fmap超过TextByteString,因为它们不是函子。
    • @chi 我会用更好的例子替换它们。
    • @TheInnerLight 您能否举一个将其应用于数据树类型的二叉树的示例 Tree a = Empty |节点a(树a)(树a)?
    【解决方案3】:

    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的回答。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-02-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-07-14
      • 1970-01-01
      • 2022-06-16
      • 2021-06-14
      相关资源
      最近更新 更多