haskell - 即使只有一个实例,Haskell 中的类型解析也会报告歧义
问题描述
我正在 Haskell 中尝试传递类型类实例。众所周知,不能在原始类型类(即(C a b, C b c) => C a c
)中声明传递实例。因此,我尝试定义另一个代表原始类的传递闭包的类。最小代码如下:
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
module Ambig where
class Coe a b where
from :: a -> b
class CoeTrans a b where
from' :: a -> b
instance CoeTrans a a where
from' = id
instance (Coe a b, CoeTrans b c) => CoeTrans a c where
from' = from' . from @a @b
instance Coe Bool Int where
from False = 0
from True = 1
instance Coe Int Integer where
from x = toInteger x
CoeTrans
的传递闭包在哪里Coe
。但是,当我尝试使用from'
inCoeTrans
时,它总是报告歧义:
-- >>> from' True :: Integer
-- Ambiguous type variable ‘b0’ arising from a use of ‘from'’
-- prevents the constraint ‘(Coe Bool b0)’ from being solved.
-- Probable fix: use a type annotation to specify what ‘b0’ should be.
-- These potential instance exist:
-- instance Coe Bool Int
-- -- Defined at /Users/t/Desktop/aqn/src/Ambig.hs:21:10
即使实际上只有一个实例。但是根据GHC 文档,如果有一个适用的实例,类型类解析将成功。
为什么会发生这种情况,有没有办法解决传递实例问题?
解决方案
我认为您误解了文档。他们确实说,如果存在一个实例,则给定类型的类型类解析将成功。但在你的情况下,没有给出类型。b0
是模棱两可的。
b0
编译器在选择 的实例之前需要知道Coe Bool b0
,即使当前范围内只有一个实例。这是故意这样做的。其中的关键词是“当前范围”。您会看到,如果编译器只能选择范围内可用的任何内容,您的程序将容易受到范围内细微变化的影响:您可能会更改导入,或者某些导入的模块可能会更改其内部结构。这可能会导致您当前范围内出现或消失不同的实例,这可能会导致您的程序的不同行为而没有任何警告。
如果您真的打算在任何两种类型之间始终最多有一个明确的路径,您可以通过添加一个函数依赖来解决它Coe
:
class Coe a b | a -> b where
from :: a -> b
这将产生两个影响:
- 编译器会知道它总是
b
可以通过知道来推断a
。 - 为了促进这一点,编译器将禁止定义具有相同
a
但不同b
s 的多个实例。
现在编译器可以看到,由于from'
is的参数Bool
,它必须搜索 for Coe Bool b
some的一个实例b
,并且从那里它会确定必须是什么b
,然后它可以从那里搜索下一个实例,依此类推.
另一方面,如果您真的打算在两个给定类型之间有多个可能的路径,并且编译器只选择一个 - 你就不走运了。编译器原则上拒绝随机选择多种可能性之一 - 请参阅上面的解释。
推荐阅读
- android-jetpack-compose - 键盘打开时Jetpack-compose Scaffold滚动bottomBar
- webhooks - webhook 徽标实际上是 webhook 的徽标吗?
- python - pycharm中的conda环境找不到专用的python解释器
- coldfusion - ColdFusion 5 安装文件
- javascript - 如何仅在对 Firestore 集合具有值时才包含要查询的条件
- html - 在闪亮中加入html标签
- html - 如何在 HTML5 中定位图像?
- robotframework - 如何使用机器人脚本计算输出 csv 文件的列
- excel - 在Excel行中的字符串中提取单词
- c# - 如何在 C# 数组中的字符串的特定索引处打印一个字母?