组成两个函数是什么意思?

问题描述 投票:24回答:5

Exercise 5 of the Haskell Typeclassopedia Section 3.2要求在声明中提供证据或反例

两个Functors的组合也是一个Functor。

我一开始以为这是在讨论组成由fmap的两个独立实例定义的Functor方法,但这并没有真正意义,因为就我所知,类型不会匹配。对于两种类型ff'fmap的类型将是fmap :: (a -> b) -> f a -> f bfmap :: (a -> b) -> f' a -> f' b,并且这看起来并不真实。那么组成两个Functors意味着什么?

haskell theory functor
5个回答
26
投票

Functor给出了两个映射:一个在类型级别上映射类型到类型(这是x中的instance Functor x where),另一个在计算级别上映射函数到函数(这是x中的fmap = x)。您正在考虑编写计算级映射,但应考虑编写类型级映射;例如,给定

newtype Compose f g x = Compose (f (g x))

你能写吗

instance (Functor f, Functor g) => Functor (Compose f g)

?如果没有,为什么不呢?


15
投票

这就是[]Maybe等类型构造函数的组合,而不是像fmap这样的函数的组合。例如,有两种组合[]Maybe的方法:

newtype ListOfMabye a = ListOfMaybe [Maybe a]
newtype MaybeOfList a = MaybeOfList (Maybe [a])

两个Functors的组成是Functor的说法意味着有一种公式化的方式为这些类型编写Functor实例:

instance Functor ListOfMaybe where
    fmap f (ListOfMaybe x) = ListOfMaybe (fmap (fmap f) x) 

instance Functor MaybeOfList where
    fmap f (MaybeOfList x) = MaybeOfList (fmap (fmap f) x)

实际上,Haskell平台附带了Data.Functor.Compose模块,它为您提供了一个“免费”执行此操作的Compose类型:

import Data.Functor.Compose

newtype Compose f g a = Compose { getCompose :: f (g a) }

instance (Functor f, Functor g) => Functor (Compose f g) where
    fmap f (Compose x) = Compose (fmap (fmap f) x)

ComposeGeneralizedNewtypeDeriving扩展特别有用:

{-# LANGUAGE GeneralizedNewtypeDeriving #-}

newtype ListOfMaybe a = ListOfMaybe (Compose [] Maybe a)
   -- Now we can derive Functor and Applicative instances based on those of Compose
   deriving (Functor, Applicative)

请注意,两个Applicatives的组成也是Applicative。因此,由于[]MaybeApplicatives,Compose [] MaybeListOfMaybe也是如此。编写Applicatives是一种非常简洁的技术,这些技术现在正逐渐变得越来越普遍,作为monad变换器的替代品,适用于不需要monad全部功能的情况。


13
投票

在这里考虑分类解释确实很有帮助,一个函子F: C -> D将对象(值)和态射(函数)从类别C中的对象和态射带到类别D中的对象和态射。

对于第二个仿函数G : D -> E,仿函数G . F : C -> E的组成只是将F fmap转换的密码域作为G fmap转换的域。在Haskell中,这是通过一个新的类型展开来完成的。

import Data.Functor

newtype Comp f g a = Comp { unComp :: f (g a) }

compose :: f (g a) -> Comp f g a
compose = Comp

decompose :: Comp f g a -> f (g a)
decompose = unComp

instance (Functor f, Functor g) => Functor (Comp f g) where
  fmap f = compose . fmap (fmap f) . decompose

12
投票

两个函数的组合是当你将一个函数放在另一个函数中时,例如

round (sqrt 23)

这是roundsqrt这两个函数的组合。类似地,两个仿函数的组合是当你将一个仿函数放在另一个仿函数中时,例如

Just [3, 5, 6, 2]

List是一个仿函数,Maybe也是。如果你试图找出fmap应该对上面的值做什么,你可以得到一些直觉来解释为什么他们的作品也是一个仿函数。当然它应该映射内部仿函数的内容!


0
投票

我相信这些答案很棒,但除了提示之外,它们对我没有任何意义(也许我需要咖啡)。我对可能位于同样位置的人的贡献如下:

根据路易斯·卡西利亚斯和其他人的说法,Functor的成分是将一个Functor放入另一个中。因此,鉴于Functor,由Array of List组成的Array of Maybe,需要实施fmap,以便:

(Array of List)  o  (Array of Option)  ==  Array of (List of Option)

具体来说,fmapArray of ListfmapArray of Option相当于fmapArray of (List of Option)。这意味着,外部fmap使用内部Functorfmap并且不使用其他方法将其功能应用于给定的内部Functor元素。

根据这个问题,这里的关键是fmap从不接触内部Functor的值,而只是依次将给予fmap的函数应用于它们中的每一个。因此,fmap不对组合施加任何类型限制。这成为映射的任何函数的责任。

© www.soinside.com 2019 - 2024. All rights reserved.