【问题标题】:Generalize the function泛化函数
【发布时间】:2017-07-03 12:26:27
【问题描述】:

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

考虑跟随代码sn-p:

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

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

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

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

【问题讨论】:

  • twiceLifted' 仅具有具体类型,因为它是使用该类型声明的。如果您删除类型声明,它将与twiceLifted 一样通用。
  • 这是在 System F 中思考的情况,具有显式的 big-lambda 抽象和类型应用程序会使其更简单。类型推断有时有点太神奇了,因为它可以为我们实例化很多类型变量,有时使过程难以遵循。

标签: haskell functional-programming


【解决方案1】:

泛化是为了减少概念的限制。考虑我们可能拥有的一个函数,它通过[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

【讨论】:

  • 因此引入类型变量(例如a)或类型约束(例如Functor)会导致类型泛化。换句话说,多态性(参数和即席)代表了类型上下文中的泛化概念。这很有趣。
猜你喜欢
  • 2017-07-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-10-03
  • 2021-04-01
  • 2016-09-30
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多