haskell - Haskell 泛型。构建代表
问题描述
在尝试验证for when和, _mk
l :*: r
l = K1 _ a
fl = ((->) a)
r = K1 _ b
fr = ((->) b)
class Functor f => Mk rep f | rep -> f where
mk :: f (rep a)
instance Mk (K1 i c) ((->) c) where
mk = \x -> K1 x
instance (Mk l fl, Mk r fr) => Mk (l :*: r) (Compose fl fr) where
mk = Compose (fmap (\l -> fmap (\r -> l :*: r) mk) mk)
现在通过类型类定义mk :: f (rep _)
,我们有f = Compose ((->) a) ((->) b) = * -> a -> b -> *
and rep _ = l:*:r
so mk :: a -> b -> l:*:r
。这是我所期望的。
但是,我认为(fmap (\l -> fmap (\r -> l :*: r) mk) mk) :: a -> b -> l:*:r
并且我看不出如何将其用作第一个参数来Compose :: forall k k1. (k -> *) -> (k1 -> k) -> k1 -> *
回馈mk
??的预期签名。
另外,我发现这个答案https://stackoverflow.com/a/35424427/11998382很有帮助,但我迷路了
f :: Compose ((->) a) ((->) b) (f r)
g :: Compose ((->) c) ((->) d) (g r)
mk f g :: Compose (Compose ((->) a) ((->) b)) (Compose ((->) c) ((->) d)) ((:*:) f g r)
他们的意思是fl :: Compose ((->) a) ((->) b) (f r)
还是mk f :: Compose ((->) a) ((->) b) (f r)
?
解决方案
我们有
f = Compose ((->) a) ((->) b) = * -> a -> b -> *
等等rep _ = l:*:r
mk :: a -> b -> l:*:r
你有精神,但我想在这里狡辩一些细节。
第一:Compose ((->) a) ((->) b)
不等于任何有趣的东西,除了它自己。但是,它与其他一些有趣的类型同构。例如,Compose ((->) a) ((->) b) c
与 同构(但不等于!)a -> b -> c
。(不过,我不确定*
你的平等中的 ' 是什么或它们来自哪里。)
第二:在这种情况下,rep
(not rep _
) 被替换为l :*: r
。因此,在您替换rep a
为 的地方l :*: r
,您实际上应该替换rep a
为(l :*: r) a
(或者,直到 alpha 重命名,rep c
由(l :*: r) c
)。就像我们对 所做的那样Compose
,我们可以在这里观察到同构,即与(l :*: r) c
同构(l c, r c)
。
把这些放在一起,我们有
f (rep a)
= { alpha renaming: a is not bound (but f and rep are) }
f (rep c)
= { definition of f and rep }
Compose ((->) a) ((->) b) ((l :*: r) c)
~= { the two isomorphisms described above }
a -> b -> (l c, r c)
但是,我认为
(fmap (\l -> fmap (\r -> l :*: r) mk) mk) :: a -> b -> l:*:r
并且我看不出如何将其用作第一个参数来Compose :: forall k k1. (k -> *) -> (k1 -> k) -> k1 -> *
回馈预期的签名mk
谨防!有两个名为 的实体Compose
。一个是在类型级别,并且具有您提供的那种:
Compose :: forall k k1. (k -> *) -> (k1 -> k) -> k1 -> *
但是在计算级别还有另一个,看起来非常不同:
Compose :: f (g a) -> Compose f g a
在这种类型中,第一个Compose
是计算级别Compose
,第二个Compose
是类型级别Compose
。
Compose
定义中使用的是术语级别,而mk
不是您似乎假设的类型级别。(在这一部分中,你也没有注意和之间的区别l :*: r
,(l :*: r) c
就像最后一点一样。)所以引用语句的正确版本是:(fmap (\l -> fmap (\r -> l :*: r) mk) mk) :: a -> b -> (l:*:r) c
,所以使用 this 作为第一个参数Compose :: f (g a) -> Compose f g a
意味着Compose (fmap ... mk) :: Compose ((->) a) ((->) b) ((l:*:r) c)
。
推荐阅读
- maven - 提供范围和编译范围带来的传递依赖被计算为编译范围
- javascript - 添加后退按钮或指向图像文件页面的链接
- java - com.jayway.jsonpath.InvalidPathException:路径中不允许有空格
- scala - 如何使用我的平等比较器 GroupBy Spark DataFrame?
- angular - 无法更改当前节点的展开/折叠图标
- c# - C# 类没有打印出来
- c++ - 在 Windows 上使用 CLION 使用 openMP 编译程序
- node.js - npm 对等安装错误是什么意思?
- python - Anaconda tensorflow 包不完整?(只有几千字节的文件大小)
- asp.net-core - 如何在 Kestrel 网络服务器中使用更新的服务证书