[英]Why is `((,) r)` a Functor that is NOT an Applicative?
来自不适用的仿函数 :
一个类型构造函数,它是一个Functor但不是Applicative。 一个简单的例子是一对:
instance Functor ((,) r) where fmap f (x,y) = (x, fy)
但是如果不对
r
施加额外的限制,如何定义其Applicative
实例是没有办法的。 特别是,如何为任意r
定义pure :: a -> (r, a)
。
问题1:为什么会这样? 以下是pure
可以使用类型a -> b
函数f
:
(pure f) (pure x, pure y) = (pure x, pure f y)
从那里, pure :: a -> (r, a)
可能取决于r
是什么。 例如,如果r
是Integer
,那么您可以定义
pure x = (0 :: Integer, x)
在您的实例声明中。 那么问题是什么?
问题2:一般来说,如果F
是一个仿函数,那么总是可以定义<*>
,但是可能并不总是定义pure
吗?
假设我们有
pure :: forall r a. a -> (r, a)
那么,特别是我们有
magic :: forall r. r
magic = fst (pure ())
现在,我们可以专门化类型变量r
来获取
magic :: Void
其中Void
是没有构造函数的数据类型,这意味着
magic = undefined
但是作为类型变量(以及专门化它们的类型)不会发挥运行时角色,这意味着magic
总是未定义的。
我们发现, ((,) r)
可以是Applicative
仅适用于居住 r
而且还有更多。 对于任何这样的实例,我们都可以写
munge :: r -> r -> r
munge r0 r1 = fst ( pure (\ _ _ -> ()) <*> (r0, ()) <*> (r1, ()) )
在r
上定义二元运算符。 Applicative
法则有效地告诉我们, munge
必须是一个吸收任何一方magic
的联想算子。
这是说有一个明智的实例
instance Monoid r => Applicative ((,) r) where
pure a = (mempty, a)
(r0, f) <*> (r1, s) = (mappend r0 r1, f s)
(正是你从Monad (Writer r)
获取pure=return; (<*>)=ap
得到的结果)。
当然,一些学者会认为定义是合法的(如果没有帮助)
instance Monoid r where
mempty = undefined
mappend _ _ = undefined
-- Monoid laws clearly hold
但我认为任何明智的类型类实例都应该对语言的已定义片段做出非常重要的贡献。
答案1:
(pure f) (pure x, pure y) = (pure x, pure fy)
我不明白你的意思。 它看起来像废话: pure f
将是一对,你不能应用一对,就好像它是一个函数。
从那里,
pure :: a -> (r, a)
可能取决于r
是什么。
这正是问题所在。 r
完全一般; 实例声明说((,) r)
是所有类型r
的Functor。 这意味着你必须以某种方式实行单一pure :: a -> (r, a)
与任何类型的作品r
呼叫者可以选择。 这是不可能的,因为没有办法从稀薄的空气中召唤出任意的r
。
或者如你的引言所说:
特别是,如何为任意
r
定义pure :: a -> (r, a)
。
如果你尝试做类似的事情
pure x = (0 :: Integer, x)
你收到一个错误:
Couldn't match expected type ‘r’ with actual type ‘Integer’
‘r’ is a rigid type variable bound by
the instance declaration
at ...
答案2:
对<*>
会是什么样的? 这将是一个功能
(<*>) :: (r, a -> b) -> (r, a) -> (r, b)
(r1, f) (r2, x) = (???, f x)
但你怎么处理???
部分? 你必须在那里放一个r
值,幸运的是你有一些可用的( r1
, r2
)。 问题是(对于任意r
)没有通用的方法来组合两个值,所以你必须选择其中一个。
这就是你遇到法律问题的地方:
pure id <*> v = v
这项法律规定我们必须选择r2
来保护v
。
u <*> pure y = pure ($ y) <*> u
由于我们必须在<*>
选择r2
,因此该法律的右侧表示结果将包含u
的r
部分。 但是,与左侧,它说,我们得到什么冲突r
被返回pure y
。 ( u
是一个完全任意的对,所以pure
返回固定值总是不会匹配它。)
所以我们有一个矛盾,这意味着我们甚至不能为((,) r)
定义<*>
。 因此,你的第二个问题的答案是“不”。
也就是说,对象有一个标准的Applicative
实例,但它需要r
为Monoid
:
instance (Monoid r) => Applicative ((,) r) where
pure x = (mempty, x)
(r1, f) (r2, x) = (mappend r1 r2, f x)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.