gpt4 book ai didi

Haskell:实例中的相等约束

转载 作者:行者123 更新时间:2023-12-01 16:40:05 24 4
gpt4 key购买 nike

我正在阅读ClassyPrelude的公告并到达这里:

instance (b ~ c, CanFilterFunc b a) => CanFilter (b -> c) a where
filter = filterFunc

作者随后提到这是行不通的:

instance (CanFilterFunc b a) => CanFilter (c -> c) a where
filter = filterFunc

这对我来说很有意义,因为 c 与左侧的约束完全无关。

但是,文章中没有提到并且我不明白的是为什么这不起作用:

instance (CanFilterFunc b a) => CanFilter (b -> b) a where
filter = filterFunc

有人可以解释为什么这与第一个提到的定义不同吗?也许 GHC 类型推断的有效示例会有帮助?

最佳答案

Michael 已经在他的博客文章中给出了很好的解释,但我将尝试用一个(人为的,但相对较小的)示例来说明它。

我们需要以下扩展:

{-# LANGUAGE FlexibleInstances, TypeFamilies #-}

让我们定义一个比 CanFilter 更简单的类,只有一个参数。我定义了该类的两个副本,因为我想演示两个实例之间的行为差​​异:

class Twice1 f where
twice1 :: f -> f

class Twice2 f where
twice2 :: f -> f

现在,让我们为每个类定义一个实例。对于 Twice1 ,我们直接将类型变量固定为相同,对于 Twice2 ,我们允许它们不同,但添加一个相等约束。

instance Twice1 (a -> a) where
twice1 f = f . f

instance (a ~ b) => Twice2 (a -> b) where
twice2 f = f . f

为了显示差异,让我们定义另一个重载函数,如下所示:

class Example a where
transform :: Int -> a

instance Example Int where
transform n = n + 1

instance Example Char where
transform _ = 'x'

现在我们已经可以看到差异了。一旦我们定义了

apply1 x = twice1 transform x
apply2 x = twice2 transform x

并向 GHC 询问推断的类型,我们得到了

apply1 :: (Example a, Twice1 (Int -> a)) => Int -> a
apply2 :: Int -> Int

这是为什么呢?嗯,Twice1 的实例仅当函数的源类型和目标类型相同时才会触发。对于 transform以及给定的上下文,我们不知道。 GHC 仅在右侧匹配后才会应用实例,因此我们留下了 Unresolved 上下文。如果我们尝试说 apply1 0 ,将会出现类型错误,表明仍然没有足够的信息来解决重载。我们必须明确指定结果类型为 Int在这种情况下才能通过。

但是,在 Twice2 ,该实例适用于任何函数类型。 GHC 将立即解决它(GHC 永远不会回溯,因此如果实例明确匹配,则始终会选择它),然后尝试建立先决条件:在本例中是等式约束,然后强制结果类型为 Int并允许我们解决 Example约束也。我们可以说apply2 0没有进一步的类型注释。

因此,这是关于 GHC 实例解析的一个相当微妙的点,这里的等式约束有助于 GHC 的类型检查器以一种需要用户更少类型注释的方式进行。

关于Haskell:实例中的相等约束,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11553705/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com