概括功能

时间:2017-07-03 12:26:27

标签: haskell functional-programming

我正在学习haskell并尝试理解泛化在函数式编程中的含义。

请考虑以下代码段:

twiceLifted :: (Functor f1, Functor f) =>
               f (f1 a) -> f (f1 Char)
twiceLifted = (fmap . fmap) replaceWithP

twiceLifted' :: [Maybe String] -> [Maybe Char]
twiceLifted' = twiceLifted

如您所见,第一个函数没有具体类型,必须实现仿函数。

第二个功能看起来更有趣。它重用了第一个函数,但它有一个具体的类型 因此,第一个功能为第二个功能奠定了基础 这是函数式编程的全部概括,重用已经存在并构建于其上的东西吗?

1 个答案:

答案 0 :(得分:3)

概括是指使概念限制性降低。考虑一下我们可能拥有的函数,它通过[Int]并向每个元素添加5

mapAdd5 :: [Int] -> [Int]
mapAdd5 [] = []
mapAdd5 (x:xs) = (x + 5) : mapAdd5 xs

好的,如果我们希望能够执行更多而不仅仅是向每个元素添加5,该怎么办?如果我们想要查看整个列表,而是将每个元素乘以2

,该怎么办?
mapMult2 :: [Int] -> [Int]
mapMult2 [] = []
mapMult2 (x:xs) = (x * 2) : mapMult2 xs

您可能注意到的一点是,我们实质上是将Int -> Int类型的函数应用于每个元素。好?

mapInts :: (Int -> Int) -> [Int] -> [Int]
mapInts f [] = []
mapInts f (x:xs) = (f x) : mapInts f xs

很好,我们现在已经将内部功能概括掉了。但是,如果我们希望能够将此概念应用于Double -> Double甚至String -> String,该怎么办?

mapMore :: (a -> a) -> [a] -> [a]
mapMore f [] = []
mapMore f (x:xs) = (f x) : mapMore f xs

如果我们不将函数限制为a -> a类型,该怎么办?也就是说,我们当前强制输出类型与输入类型相同。如果它们可能不同,如a -> b,该怎么办?虽然可能非常好ab相同,但与a -> a不同,我们并不强迫它如此:

map :: (a -> b) -> [a] -> [b]
map f [] = []
map f (x:xs) = (f x) : map f xs

现在我们已经从mapAdd5推广到map

<强>加成

如果我们不想限制自己使用列表怎么办?事实证明,我们可以将列表抽象/概括为Functor的实例,这些实例只是使函数能够应用于包装/保存其他项的类型。想一想,这正是列表的作用!

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

fmap如何定义?其定义将根据您拥有的容器f的类型而有所不同。但是,对于列表(也称为[]),我们将其定义为here

instance Functor [] where
    fmap = map