instance Functor [] where
fmap f (x : xs) = f x : fmap xs
fmap _ [] = []
instance Functor Maybe where
fmap f (Just x) = Just (f x)
fmap _ Nothing = Nothing
instance Functor ((,) a) where
fmap f (x, y) = (x, f y)
现在Functor的return怎么样了? 清单:
instance Functor [] where
return x = [x]
好吧。那也许呢?
instance Functor Maybe where
return x = Just x
好的。现在元组:
instance Functor ((,) a) where
return x = (??? , x)
5条答案
按热度按时间ugmeyewa1#
首先,有两个层次:类型和值。由于Hask的对象是类型,因此只能使用类型构造函数来Map它们,类型构造函数的类型为
* -> *
:α -> F α
(对于Functor F
),β -> M β
(用于Monad M
)。然后对于函子,你需要态射(即函数,是值)上的Map:它只是
fmap :: (α -> β) -> (F α -> F β)
。到目前为止,我想,我并没有说什么新的东西。但是重要的是,
Monad
的return :: α -> M α
并不像你所想的那样是α
到M α
的Map器。关于单子的数学定义,return
对应于从Id
函子到M
函子的自然变换,只是这个Id
函子是隐式的。单子的标准定义还需要另一个自然变换M ◦ M -> M
,所以把它翻译成Haskell就像(As旁注:这两个自然变换实际上是单位变换和乘法变换,它们使单子成为内函子范畴中的幺半群。
实际的定义不同,但是等效的。请参阅Haskell/wiki。
如果您使用从标准bind
>>= :: m α -> (α -> m β) -> m β
派生的类似于复合的运算符:你可以看到,这实际上都是关于Kleisli category的,也可以参考article on nLab关于计算机科学中的单子。
p5fdfcr12#
一个类别的对象和面向对象编程语言中的对象不一样(我们更喜欢在Haskell中调用那些值;它们在范畴论中的意义已经讨论过here)。相反,Hask的对象是 types。Haskell
Functor
s是Hask中的内函子,即通过以下方式将类型与类型相关联:前奏曲〉:k也许
可能是::* -〉*
前奏曲〉:k Int
输入::*
前奏曲〉:k也许Int
可能是Int::*
OTOH,Hask的 * 箭头 * 实际上是一些函数类型
a -> b
的值。它们以如下方式关联:dfuffjeb3#
虽然你在问题中使用了那些花哨的分类术语,并且应该对现有的答案完全满意,但这里还是试图给出一个相当琐碎的解释:
假设在Functor类型类中 * 将 * 有一个函数
return
(或pure
或unit
或...
)。现在试着定义一些常见的Functor示例:
[]
(列表)、Maybe
、((,) a)
(具有左组件的元组)很简单吧?
下面是普通的Functor示例:
现在Functor的
return
怎么样了?清单:
好吧。那也许呢?
好的。现在元组:
你看,我们不知道应该把哪个值填入元组的左边部分。示例声明说它有一个
a
类型,但我们不知道该类型的值。也许类型a是只有一个值的Unit
类型。但如果它是Bool
,我们应该取True
还是False
?如果是Either Int Bool
,我们应该取Left 0
,还是Right False
,还是Left 1
?所以你看,如果你在Functor上有一个
return
,一般来说你不能定义很多有效的functor示例(你需要施加一个像FunctorEmpty类型类的约束)。如果你看一下
Functor
和Monad
的文档,你会发现确实有Functor ((,) a)
的示例,但没有Monad ((,) a)
的示例,这是因为你不能为那个东西定义return
。ivqmmu1c4#
如果您有
那么类型构造函数
F
是对对象(是类型)采取类型T
到类型F T
的动作,而fmap
是对态射(是函数)采取函数f :: T -> U
到fmap f :: F T -> F U
的动作。z9smfwbn5#
在范畴论中,函子将所有对象从一个范畴Map到另一个范畴,但函子并不Map对象中的元素。