gpt4 book ai didi

haskell - 使用不包含在类头中的不明确类型变量实现实例方法

转载 作者:行者123 更新时间:2023-12-02 14:55:04 24 4
gpt4 key购买 nike

假设我有两个这样的类(class):

{-# LANGUAGE MultiParamTypeClasses, AllowAmbiguousTypes, FlexibleContexts #-}
class Foo a b

class Bar a where
foo :: Foo a b => a

值得注意的是,bfoo也不能从 foo 的使用中推断出也不是来自实例头。现在让我们尝试为此实现一个实例:

data A = A

-- This implementation doesn't actually need the Foo A b constraint, but for the sake of the question it's required here.
a :: Foo A b => A
a = A

到目前为止一切顺利。 a应该成为foo在我们的例子中。它甚至有正确的类型,对吧?那么让我们继续实现该实例:

instance Bar A where
foo = a

不幸的是,这个实例无法编译并给出以下错误:

instance-ambiguous.hs:15:9: error: …
• Could not deduce (Foo A b0) arising from a use of ‘a’
from the context: Foo A b
bound by the type signature for:
foo :: forall b. Foo A b => A
at /home/sven/instance-ambiguous.hs:15:3-5
The type variable ‘b0’ is ambiguous
• In the expression: a
In an equation for ‘foo’: foo = a
In the instance declaration for ‘Bar A’
|
Compilation failed.

乍一看,这个错误消息似乎很 absurd ,因为看起来 GHC 可以统一 bb0并推断出一个完美的类型。然后我想起了bb0foo 的类型中看不到或a GHC 无法统一它们,因为它无法保证 bb0实际上总是完全相同,并且在处理不明确的类型时这并不是一个意外的错误。

通常,当我遇到此类错误时,我可以使用 TypeApplications 和 ScopedTypeVariables 来解决它们,如下所示:

{-# LANGUAGE MultiParamTypeClasses, AllowAmbiguousTypes, FlexibleContexts, TypeApplications, ScopedTypeVariables #-}

class Foo a b

class Bar b

foo :: forall b a. (Bar b, Foo a b) => a
foo = undefined

bar :: forall b a. (Bar b, Foo a b) => a
bar = foo @b

在这里我可以明确提供@b ,因为 bar 的类型签名将其纳入范围。所以我尝试对我的实例执行相同的操作(使用 InstanceSigs):

instance Bar A where
foo :: forall b. Foo A b => A
foo = a @b

这也不会编译并给出此错误:

instance-ambiguous.hs:16:10-31: error: …
• Could not deduce (Foo A b0)
from the context: Foo A b
bound by the type signature for:
foo :: forall b. Foo A b => A
at /home/sven/instance-ambiguous.hs:16:10-31
The type variable ‘b0’ is ambiguous
• When checking that instance signature for ‘foo’
is more general than its signature in the class
Instance sig: forall b. Foo A b => A
Class sig: forall b. Foo A b => A
In the instance declaration for ‘Bar A’
|
Compilation failed.

我不确定,但我认为这意味着 GHC 认为我的 Foo A b => A在实例中指的是其他一些b比类声明中的那个要多。

foo 上使用模式声明获取原件b in 作用域也不起作用,因为实例声明中禁止模式绑定(bind)。

现在的问题是:我有什么选择来解决这个问题?

我知道我可以使用 Proxy (s/y/ie/) 无处不在,听不到任何歧义问题,但我通常发现 TypeApplications 比 Proxy 更优雅。 s 并希望在这里使用它们,特别是因为受影响的类是我的公共(public) API 的一部分。

我还可以包括 b作为 Bar 的类变量,但我认为这会改变 Bar 的含义到我不想要的东西,因为这样实例就可以选择哪个 b s 来实现实例,但我想要每个 Bar a => a为每个b工作其中 Foo a b存在。

最佳答案

似乎没有办法解决实例的歧义,因此 ProxyTagged 似乎不可避免地要定义该类,但您可以包装它使用该类与TypeApplications

class Bar a where
foo_ :: Foo a b => proxy b -> a

foo :: forall b a. (Bar a, Foo a b) => a
foo = foo_ (Proxy @b)

关于haskell - 使用不包含在类头中的不明确类型变量实现实例方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54470002/

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