提问人:akbiggs 提问时间:11/5/2013 最后编辑:recursion.ninjaakbiggs 更新时间:8/28/2021 访问量:5390
组成两个函子是什么意思?
What does it mean to compose two Functors?
问:
Haskell Typeclassopedia 第 3.2 节的练习 5 要求对语句进行证明或反例
两个函子的组成也是一个函子。
起初我以为这是在谈论由两个单独的实例定义的方法,但这并没有真正的意义,因为据我所知,这些类型不会匹配。对于两种类型 和 ,的类型将是 和 ,这似乎不是真正可组合的。那么组成两个意味着什么呢?fmap
Functor
f
f'
fmap
fmap :: (a -> b) -> f a -> f b
fmap :: (a -> b) -> f' a -> f' b
Functors
答:
A 给出了两个映射:一个是类型级将类型映射到类型(这是 in ),另一个是计算级将函数映射到函数(这是 in )。您正在考虑编写计算级映射,但应该考虑编写类型级映射;例如,给定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)
?如果不是,为什么不呢?
评论
两个函数的组成是将一个函数放在另一个函数中,例如
round (sqrt 23)
这是两个函数和 的组成。同样,两个函子的组成是将一个函子放在另一个函子中,例如round
sqrt
Just [3, 5, 6, 2]
List 是一个函子,也许也是如此。如果你试图弄清楚 fmap 应该对上述值做什么,你可以得到一些直觉,为什么它们的组合也是一个函子。当然,它应该映射到内部函子的内容上!
考虑这里的分类解释确实很有帮助,函子将对象(值)和形态(函数)带到对象,将形态从一个类别带到一个类别中的对象和形态。F: C -> D
C
D
对于第二个函子,函子的组合只是将变换的共域作为变换的域。在Haskell中,这是通过一些新类型的解包来实现的。G : D -> E
G . F : C -> E
F
fmap
G
fmap
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 foo = compose . fmap (fmap foo) . decompose
评论
f
functor
function
Functor f
f
fmap f
这里谈论的是类型构造函数的组合,如 和 ,而不是函数的组合。因此,例如,有两种作曲方式和:[]
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)
Compose
对扩展特别有用:GeneralizedNewtypeDeriving
{-# 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)
请注意,两个 s 的组成也是一个 .因此,既然 和 是 s,那么 和 也是如此。作曲是一种非常简洁的技术,如今正慢慢变得越来越普遍,作为单子转换器的替代品,适用于不需要单子的全部功能的情况。Applicative
Applicative
[]
Maybe
Applicative
Compose [] Maybe
ListOfMaybe
Applicative
评论
newtype Compose f g a = Compose (f (g a))
f (g a)
newtype Compose f g a = MkCompose (f (g a))
fmap foo (MkCompose x) = MkCompose (fmap (fmap foo) x)
评论
:t fmap . fmap
:: (Functor f1, Functor f) => (a -> b) -> f (f1 a) -> f (f1 b)