Haskell fmap的自由定理
考虑以下包装器:Haskell fmap的自由定理,haskell,functor,category-theory,denotational-semantics,free-theorem,Haskell,Functor,Category Theory,Denotational Semantics,Free Theorem,考虑以下包装器: newtype F a = Wrap { unwrap :: Int } 我想反驳(作为一个绕过头的练习)有一个合法的函子F实例,它允许我们将Int->Int类型的函数应用于实际内容,并~ignore~所有其他函数(即fmap nonitint=id) 我认为这应该通过fmap的自由定理来实现(我读过): 对于给定的f、g、h和k,例如g。f=k。h:$map g。fmap f=fmap k$map h,其中$map是给定构造函数的自然贴图 什么定义了自然地图?对于F,我假设
newtype F a = Wrap { unwrap :: Int }
我想反驳(作为一个绕过头的练习)有一个合法的函子F
实例,它允许我们将Int->Int
类型的函数应用于实际内容,并~ignore~所有其他函数(即fmap nonitint=id
)
我认为这应该通过fmap
的自由定理来实现(我读过):
对于给定的f
、g
、h
和k
,例如g。f=k。h
:$map g。fmap f=fmap k$map h
,其中$map
是给定构造函数的自然贴图
什么定义了自然地图?对于F
,我假设它是一个简单的flip const
对吗
据我所知:$mapf
就是我们在范畴理论中所说的Ff
。因此,从明确的意义上讲,我们只是希望在下图中的几行中有一些东西可以通勤:
然而,我不知道用什么来代替?
s(也就是说,我们应用什么函子来得到这样一个图,以及我们如何表示这个几乎-fmap
?)
那么,一般来说,什么是自然地图,对于F
?fmap
的自由定理的正确图解是什么
我带着这个去哪里? 考虑:
f = const 42
g = id
h = const ()
k () = 42
很容易看出f。g
是h。k
。然而,不存在的fmap
将只执行f
,而不是k
,从而产生不同的结果。如果我对自然性的直觉是正确的,那么这样的证明就行了。这就是我想弄明白的
提出了一个更简单的证明:
fmap show。与fmap$show不同,fmap(+1)
更改内容。(+1)
。这是一个很好的证明,但我仍然想用自由定理作为练习。因此我们正在为所有a b提供函数m::的娱乐。(a->b)->F a->F b
这样(除其他外)
这里有两个有点相关的问题
fmap
能做到这一点吗fmap
无法做到这一点,因为fmap
必须遵守函子的公理。我们的环境是否是参数化的并不重要。函子的公理说,对于所有函数a
和b
,fmap(a.b)=fmap a。fmap b
必须保持,并且对于a=show
和b=(1+)
,此操作失败。所以m
不能是一个行为良好的fmap
参数函数不能这样做,因为这就是参数定理所说的。当将类型视为术语之间的关系时,相关函数将相关参数视为相关结果。很容易看出m
不符合参数化,但查看m':对于所有a和b稍微容易一些。(a->b)->(Int->Int)
(这两者可以简单地相互转换)(1+)
与show
相关,因为m'
的参数是多态的,所以参数的不同值可以通过任何关系关联。函数是关系,存在一个函数,它将(1+)
发送到显示
。但是,m'
的结果类型没有类型变量,因此它对应于常量关系(其值仅与自身相关)。由于包括m'
在内的每个值都与自身相关,因此所有参数函数m::对于所有a b。(a->b)->(Int->Int)
必须遵守mf=mg
,即必须忽略第一个参数。这在直觉上是显而易见的,因为没有什么可以应用它
事实上,通过观察行为良好的fmap
必须是参数化的,可以从第二个语句推断出第一个语句。因此,即使该语言允许非参数化,fmap
也不能对其进行任何不寻常的使用。我看不出这种自然地图的东西将走向何方。您只需要为您描述的函子实例显示一个反例,fmap f。fmap g≠ fmap(f.g)
。这很容易。如何编写一个区分f::Int->Int
和f
的所有其他函数类型的fmap f(Wrap x)
。因此,我们采用g=(+1)
和f=show
,因此fmap(f.g)
不会改变内容,这与fmap f不同。fmap g
。谢谢,但我仍然想用自由定理来做这件事,正如我在文章中提到的,这只是一个练习,用自由定理来理解整个事情:)。另外,如果我对自然性的理解是正确的,那么使用无自由度定理的证明就不难了:请考虑<代码> f= const 42 ,<代码> g= id < /c>,<代码> h=const()/<代码>和<代码> k~()=42 < /代码>。我将把这两个证明都添加到帖子中。@Michhawiedenmann one不能,这就是我们试图正式证明的:)。const 42
有类型Int->Int
,也有类型()->Int
和任何类型a->Int
,适用于所有类型a
。fmap(const 42)(Wrap 0)
应该是什么?啊哈,所以,总而言之,我试图通过类别来实现这一点是错误的,因为类别理论不需要参数(请参见你在主帖子下的评论)。正确的方法是考虑这个代码<代码> fmap <代码>是箭头的函数映射,并显示<代码> fmap(a,b)=fmap a。fmap b
法律不成立。我是否正确描述了我的错误?@ZhiltsoffIgor事实上,fmap
似乎需要参数,因为fmap(f.g)=fmap f。fmap g
严格比
m (1 +) (Wrap x) = (Wrap (1+x))
m (show) (Wrap x) = (Wrap x)