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

时间:2013-11-04 18:30:20

标签: haskell theory functor

Exercise 5 of the Haskell Typeclassopedia Section 3.2要求在声明

上提供证明或反例
  

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

我首先想到的是,这是关于编写由fmap的两个独立实例定义的Functor方法,但这并没有真正意义,因为类型不匹配据我所知。对于ff'这两种类型,fmap的类型将是fmap :: (a -> b) -> f a -> f bfmap :: (a -> b) -> f' a -> f' b,这看起来并不真实。那么撰写两个Functors是什么意思?

5 个答案:

答案 0 :(得分:26)

A 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)

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

答案 1 :(得分: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)

请注意,两个Applicative的组合也是Applicative。因此,[]MaybeApplicativeCompose [] MaybeListOfMaybe也是Applicative。组合{{1}}是一种非常简洁的技术,这些技术近来逐渐变得越来越普遍,作为monad变换器的替代品,适用于不需要monad全部功能的情况。

答案 2 :(得分:13)

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

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

fmap

答案 3 :(得分:12)

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

round (sqrt 23)

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

Just [3, 5, 6, 2]

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

答案 4 :(得分:0)

我确信这些答案是不错的,但对我来说,除了暗示之外,对我没有任何意义(也许我需要喝咖啡)。我对可能位于类似位置的人的贡献如下:

根据路易斯·卡西利亚斯(Luis Casillas)等人的说法,

Functor的组成是将一个Functor放在另一个内部。因此,给定由Functor组成的Array of ListArray of Maybe,要求实现fmap以便:

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

具体来说,fmap的{​​{1}}和Array of List的{​​{1}}等同于fmap的{​​{1}}。也就是说,外部Array of Option使用内部fmap的{​​{1}},而不使用其他方式将其功能应用于给定内部Array of (List of Option)的元素。

对于每个问题,这里的关键是fmap永远不会触及内部Functor的值,而只会将fmap赋予的功能依次应用于每个值。因此,Functor不会对合成施加任何类型约束。这就是要映射的任何函数的责任。