【问题标题】:Haskell kind system vs type families and multi param type classesHaskell 种类系统与类型系列和多参数类型类
【发布时间】:2019-12-25 18:56:54
【问题描述】:

在 Haskell 中,我发现很难完全理解 kind 系统的目的,以及它真正为语言添加了什么。

我知道有种类会增加安全性。 例如,考虑 fmap :: (a -> b) -> f a -> f b 与它的单一版本 fmap2 :: (a -> b) -> p -> q

我的理解是,多亏了 kind 系统,我可以更详细地预先指定数据的形状应该是什么。更好,因为类型检查器可以检查更多,更严格的要求将减少用户弄乱类型的可能性。这将减少编程错误的可能性。我相信这是种类的主要动机,但我可能错了。

现在我认为 fmap2 可以具有与 fmap 相同的实现,因为它的类型不受约束。是真的吗?

是否可以将 base/ghc 库中的所有多类型类型替换为单类型类型,并且仍然可以正确编译?

为了澄清一点,我的意思是对于像这样的类:

class  Functor f  where
    fmap        :: (a -> b) -> f a -> f b
    (<$)        :: a -> f b -> f a

我可能会用类似的东西替换它

class  Functor a b p q  where
    fmap        :: (a -> b) -> p -> q
    (<$)        :: a -> q -> p

这种方式适用于Functor 这样的实例

instance Functor [] where fmap = map

我可能会替换为

instance Functor a b p q where fmap = map

备注:这不会按原样工作,因为我还需要修改 map 并沿着依赖链向下走。稍后会考虑更多..

我想弄清楚种类是否不仅仅增加了安全性?我可以用多类类型做一些我不能用单类做的事情吗?

备注:在这里我忘了提到我通常使用一些语言扩展,通常是为了在编写类时提供更大的灵活性。 当做香草haskell种类时,使用起来真的很有意义。 但是当我开始使用类型族和其他一些扩展时,我根本不需要种类就变得不那么清楚了。

我记得有一些可单遍历的库,它使用单一种类的类型重新实现了许多标准库函数,并使用类型族来概括签名。这就是为什么我的直觉是,如果一个使用类型族,多类型变量可能不会真正增加那么多的表达能力。然而,这样做的一个缺点是你失去了类型安全性。我的问题是你真的只是失去了那个,还是你真的失去了其他东西。

【问题讨论】:

  • @WillemVanOnsem 是的,所以我是否正确地说 fmap2 比 fmap 更通用,并且它的实现可能相同?
  • 我不是类型论专家,我一直在看这篇文章en.wikipedia.org/wiki/Kind_(type_theory),但我很难理解为什么整个类型系统确实存在的深层原因
  • 既然有基于类型的函数级编程,就有基于种类的类型级编程,甚至将来可能存在基于排序的种类级编程。 Types and Kinds and Sorts, Oh My! 是一本好书。
  • @J.M.你不正确。比较通用,但是不能实现。
  • fmap 的完整类型实际上比您在问题中所说的要长:fmap :: Functor f =&gt; (a -&gt; b) -&gt; f a -&gt; f b。对于您提议的替代类型,您将如何陈述类似于 Functor f 的约束?

标签: haskell type-kinds


【解决方案1】:

让我们备份。似乎您认为是因为签名

id2 :: a -> b

更通用
id :: a -> a

id2 可以与id 具有相同的实现。但事实并非如此。事实上id2 没有完整的实现(id2 的任何实现都涉及无限循环或undefined)。

一般性的结构会产生一种“压力”,而这种压力是我们必须通过导航才能找到适合某事的类型。如果fg 更通用,这意味着任何地方都可以使用gf 也可以,但它 意味着 f 的任何实现都是g 的有效实现。所以在使用站点是一个方向,在定义站点是另一个方向。

我们可以在任何可以使用id 的地方使用id2,但是id2 的签名太笼统以至于无法实现。签名越通用,它可以使用的上下文越多,但实现的可能性也就越小。我想说一个好的类型签名的主要目标是找到一个通用性级别,其中尽可能少实现您的预​​期功能,而不会完全写不出来。

您提议的签名fmap2 :: (a -&gt; b) -&gt; p -&gt; qid2 一样,太笼统以至于无法实施。更高种类的类型的目的是为我们提供具有非常通用签名的工具,例如 fmap,它们不像 fmap2 那样通用。

【讨论】:

  • 公平地说,问题中建议的类型fmap :: (a -&gt; b) -&gt; f a -&gt; f b 也无法实现。 (这不是 fmap 在 Haskell 中的类型。)所以人们可能想首先弄清楚 OP 为 fmap2 考虑的上下文。
  • @DanielWagner,是的。这个答案写起来很费劲,我必须一次覆盖太多的内容。我想看看 OP 如何响应并从那里获取...
  • 完全公平。我也开始写答案,并且出于类似的原因而苦苦挣扎。
  • @luqui 如果我使用类型族怎么办:type family ElemOf x :: *我不能实现fmap3 :: (ElemOf p -&gt; ElemOf q) -&gt; p -&gt; q吗?
  • @luqi 好的,如果我有这个:```class AAA a b where id2 :: a -> b ```没有什么能阻止我这样做``` instance AAA a a where id2 = id ```对吧?类似地,而不是这样:``` class Functor f where fmap :: (a -> b) -> f a -> f b ```我可以有这个 ``` class Functor a b p q where fmap :: (a -> b ) -> p -> q ``` 好的,我正在添加参数,但我可以为每个 Functor 实例保留相同的代码吗?
猜你喜欢
  • 2012-06-29
  • 1970-01-01
  • 2012-11-11
  • 1970-01-01
  • 2015-06-27
  • 1970-01-01
  • 2013-11-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多