Haskell 为什么扩展函数依赖项会消除非类型变量参数?

Haskell 为什么扩展函数依赖项会消除非类型变量参数?,haskell,ghc,functional-dependencies,Haskell,Ghc,Functional Dependencies,我一直在做一些工作来构建自己的定制prelude,我想构建一个可调用的类型类,该类将为函数以外的类型实现函数应用程序(($))。因此,我使用多参数类型类构建了一个类型类: {-#语言多段类型类} 导入序曲() 类可调用a b c,其中 ($)::a->b->c 现在,我继续将函数作为Callable类型类的实例,这要求我启用灵活的实例 {-#语言MultiparamTypeClass,FlexibleInstances} 导入序曲() id::a->a id x=x 类可调用a b c,其中

我一直在做一些工作来构建自己的定制prelude,我想构建一个
可调用的
类型类,该类将为函数以外的类型实现函数应用程序(
($)
)。因此,我使用多参数类型类构建了一个类型类:

{-#语言多段类型类}
导入序曲()
类可调用a b c,其中
($)::a->b->c
现在,我继续将函数作为
Callable
类型类的实例,这要求我启用灵活的实例

{-#语言MultiparamTypeClass,FlexibleInstances}
导入序曲()
id::a->a
id x=x
类可调用a b c,其中
($)::a->b->c
实例可调用(a->b)a b其中
($)=id
这很好,现在我可以在函数上使用
($)
。因此,我的下一个逻辑步骤是实现函数组合(
()
)。在做了一点修改之后,我意识到为了做到这一点,我需要使
可调用
函数依赖性,所以我打开了函数依赖性

{-#语言多段类型类、灵活实例、功能依赖性#-}
导入序曲()
id::a->a
id x=x
类可调用的AB c | AB->c其中
($)::a->b->c
实例可调用(a->b)a b其中
($)=id
(.):(可调用f1 intype INTERNATE,可调用f2 INTERNATE outtype)=>f2->f1->intype->outtype
(.)AB c=a$(b$c)
这确实很好。事实上,如果我能用我的
(.)
生成函数。然而,如果我尝试使用我的新函数(至少以我尝试过的任何方式),它都无法进行类型检查,并出现一个相当隐晦的错误

~/p/dynamo>ghci callable.hs
GHCi,8.4.2版:http://www.haskell.org/ghc/  :? 求救
[1/1]编译Main(callable.hs,已解释)
好的,加载了一个模块。
*Main>:t(id)。(id)
(身份证)。(身份证)
:(可调用(a1->a1)CE,可调用(a2->a2)ED)=>c->d
*Main>((id)。(id))$()
:2:1:错误:
•非类型变量参数
在约束中:可调用(c1->d)()c2
(使用flexibleContext允许此操作)
•检查推断类型时
it::对于所有c1 d c2 a1 e a2。
(可调用(c1->d)c2,可调用(a1->a1)c1e,
可调用(a2->a2)ED)=>
c2
*Main>
我真的无法理解这个错误想要传达什么。但它建议我打开灵活的上下文,所以我想我应该尝试一下,如果它解决了问题,这很好,如果它改变了我可能在问题上遇到的错误。然而,如果我打开灵活的上下文,错误不会改变,事实上,它甚至仍然建议我打开灵活的上下文

在这一点上,我想我会做一些阅读。我读了一些关于
非类型变量参数的问题,但我并不觉得自己对自己的问题有什么见解。正是在这一点上,我内心深处的某种想法让我认为
b
也是一种功能依赖。我不知道为什么,但这确实解决了我的问题。下面是工作代码的样子:

{-#语言多段类型类、灵活实例、功能依赖性#-}
导入序曲()
id::a->a
id x=x
类可调用的ABC | a->BC其中
($)::a->b->c
实例可调用(a->b)a b其中
($)=id
(.):(可调用f1 intype INTERNATE,可调用f2 INTERNATE outtype)=>f2->f1->intype->outtype
(.)AB c=a$(b$c)

所以我的问题当然是,这到底是怎么回事?我做错了什么?更改是如何修复的?

您需要在ghci中启用
FlexibleContexts
。ghci不会仅因为在您加载的文件中使用了扩展名就以交互方式启用扩展名。有时候有点尴尬,但我明白为什么。您可以一次加载多个文件,每个文件都可以指定不同的扩展名,而且您可能不希望所有扩展名都合并,因为有些扩展名与其他扩展名不兼容

您可以在命令行中使用
-XFlexibleContexts
调用ghci,也可以在ghci中使用
:set-XFlexibleContexts
启用它


至于为什么一开始就要求你启用它?哈斯克尔对语境的形式有非常严格的规定。这些限制性规则源于历史上的担忧,即放松这些规则可能会增加实施的复杂性。事实证明,放松它们并没有坏处,这就是扩展所做的。我甚至不记得它应该保护什么-如果编译器要求,我会打开扩展。

对于fundep
ab->c
,你是说函数类型(
a
)和参数类型(
b
)决定结果类型(
c
)。将其更改为
a->bc
意味着函数类型确定了参数和结果类型,这就是您想要的:如果
a
替换为
a'->b'
b
替换为
a'
,而
c
替换为
b'
,实际上,函数类型包含了消除歧义所需的信息。

您知道,这实际上编译并运行得很好。你用的是哪种编译器?@FyodorSoikin它说,我用的是8.4.2。如果它建议打开灵活的上下文,你还没有打开它们。例如,您可以将扩展名添加到文件开头的扩展名中。