我想了解与函数有关的fmap,我想知道是否有一种“简单”的方式来写出完成相同fmap的函数,而不是从函数库中调用它?
我是Haskell的新手,因此在检查引用时,我发现很多事情我的课还没有结束-我正努力保持领先地位,因为这非常困难且动作迅速。
fmap的库定义为:
fmap :: (a -> b) -> f a -> f b
我想知道
fmap
是否可以像辅助函数一样写到实现fmap
的函数中。然后,输出将与使用
fmap
时完全相同,但是我们将其替换为完成相同任务的辅助函数。可能吗 最佳答案
fmap
是Functor
类型类的成员,其定义如下:
class Functor f where
fmap :: (a -> b) -> f a -> f b
这意味着作为
Functor
实例的每种类型都有自己的fmap
专用实现:-- For making type signatures in instances explicit
{-# LANGUAGE InstanceSigs #-}
instance Functor Maybe where
fmap :: (a -> b) -> Maybe a -> Maybe b
fmap f (Just x) = Just (f x)
fmap f Nothing = Nothing
instance Functor [] where
fmap :: (a -> b) -> [a] -> [b]
fmap f (x : xs) = f x : fmap f xs
fmap f [] = []
-- Or: fmap = map
当您以特定类型调用
fmap
时,编译器会自动选择要使用的适当实例:-- For making type arguments explicit
{-# LANGUAGE TypeApplications #-}
fmap succ (Just 1)
==
fmap @Maybe succ (Just 1)
==
Just 2
fmap succ [1, 2, 3]
==
fmap @[] succ [1, 2, 3]
==
[2, 3, 4]
当然,您可以直接使用专用功能而不是
fmap
-我们只有单独的功能fmapMaybe
,fmapList
(map
),fmapEither
,fmapIO
,依此类推。但是,通常使用fmap
或类型类的优点是,您可以编写可在该类型类的任何实例上使用的多态函数:fmapBoth :: (Functor f) => (a -> b) -> f (a, a) -> f (b, b)
fmapBoth f m = fmap (\ (x, y) -> (f x, f y)) m
fmapBoth succ (Just (1, 2))
==
fmapBoth @Maybe succ (Just (1, 2))
==
Just (2, 3)
fmapBoth succ [(1, 2), (2, 3)]
==
fmapBoth @[] succ [(1, 2), (2, 3)]
==
[(2, 3), (3, 4)]
在内部,GHC通过将
fmap
的特定实现作为额外的参数传递给您定义的函数来实现此目的:fmapBoth'
:: ((a -> b) -> f a -> f b)
-> (a -> b)
-> f (a, a)
-> f (b, b)
fmapBoth' fmapF f m = fmapF (\ (x, y) -> (f x, f y)) m
fmapBoth @[] succ [(1, 2), (2, 3)]
==
fmapBoth' map succ [(1, 2), (2, 3)]
==
map (\ (x, y) -> (succ x, succ y)) [(1, 2), (2, 3)]
==
[(2, 3), (3, 4)]
因此,您可以将诸如
Num a => …
或Functor f => …
之类的类型类约束视为函数的附加参数,碰巧是由编译器隐式传递的,其中包含特定类型类中所有方法的记录。 (实际上,ImplicitParams
扩展名使您可以将此机制用于任何类型的隐式参数,尽管该扩展名并未得到广泛使用,因为通常有更好的替代方法,例如Reader
。)使用
fmap
代替专用功能的部分优势在于,它使您可以“编码到接口,而不是实现”(例如,如果您在程序中使用列表,并且以后又想更改为Vector
出于性能原因,如果在所有地方都使用了fmap
之类的多态函数,则只需换出类型,代码就可以继续工作而无需进行修改-但是,如果您对列表使用了map
特定项,则您将需要更新每个呼叫站点。类型类的最初目的是避免为比较(
Eq
和Ord
)和算术(Num
)之类的东西提供专门的功能,如果我们没有这种多态性,那么我们将需要单独的函数,如,eqInt
,eqFloat
和&c。到处。类型类使我们可以对此进行抽象并编写eqChar
而不管特定的类型如何,并使编译器插入对适当函数的调用。关于haskell - 可以将fmap编写为函数而不是从库中调用吗?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/55638219/