gpt4 book ai didi

haskell - GHC 7.7 中引入的自由覆盖条件破坏了 GHC 7.6 中有效的代码

转载 作者:行者123 更新时间:2023-12-04 04:05:34 26 4
gpt4 key购买 nike

想法

我正在写 DSL ,编译为 Haskell。

该语言的用户可以定义自己的不可变数据结构和相关函数。关联函数是指属于数据结构的函数。
例如,用户可以编写(在“pythonic”伪代码中):

data Vector a:
x,y,z :: a
def method1(self, x):
return x

(这等效于以下代码,但也显示了关联函数 beheva 类似于具有开放世界假设的类型类):
data Vector a:
x,y,z :: a
def Vector.method1(self, x):
return x

在本例中, method1是与 Vector 关联的函数数据类型,可以像 v.testid(5) 一样使用(其中 vVector 数据类型的实例)。

我正在将此类代码转换为 Haskell 代码,但我遇到了一个问题,我试图解决很长时间。

问题

我正在尝试将代码从 GHC 7.6 移到 GHC 7.7 (which is pre-release of 7.8) (较新的版本可以编译 from sources )。该代码在 GHC 7.6 下完美运行,但在 GHC 7.7 下却不行。
我想问你如何修复它以使其在新版本的编译器中工作?

示例代码

让我们看看生成的(由我的编译器)Haskell 代码的简化版本:
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE FunctionalDependencies #-}

import Data.Tuple.OneTuple

------------------------------
-- data types
------------------------------
data Vector a = Vector {x :: a, y :: a, z :: a} deriving (Show)
-- the Vector_testid is used as wrapper over a function "testid".
newtype Vector_testid a = Vector_testid a

------------------------------
-- sample function, which is associated to data type Vector
------------------------------
testid (v :: Vector a) x = x

------------------------------
-- problematic function (described later)
------------------------------
testx x = call (method1 x) $ OneTuple "test"

------------------------------
-- type classes
------------------------------
-- type class used to access "method1" associated function
class Method1 cls m func | cls -> m, cls -> func where
method1 :: cls -> m func

-- simplified version of type class used to "evaluate" functions based on
-- their input. For example: passing empty tuple as first argument of `call`
-- indicates evaluating function with default arguments (in this example
-- the mechanism of getting default arguments is not available)
class Call a b where
call :: a -> b

------------------------------
-- type classes instances
------------------------------
instance (out ~ (t1->t1)) => Method1 (Vector a) Vector_testid out where
method1 = (Vector_testid . testid)

instance (base ~ (OneTuple t1 -> t2)) => Call (Vector_testid base) (OneTuple t1 -> t2) where
call (Vector_testid val) = val

------------------------------
-- example usage
------------------------------
main = do
let v = Vector (1::Int) (2::Int) (3::Int)
-- following lines equals to a pseudocode of ` v.method1 "test" `
-- OneTuple is used to indicate, that we are passing single element.
-- In case of more or less elements, ordinary tuples would be used.
print $ call (method1 v) $ OneTuple "test"
print $ testx v

该代码可以编译并与 GHC 7.6 一起正常工作。当我尝试使用 GHC 7.7 编译它时,出现以下错误:
debug.hs:61:10:
Illegal instance declaration for
‛Method1 (Vector a) Vector_testid out’
The liberal coverage condition fails in class ‛Method1’
for functional dependency: ‛cls -> func’
Reason: lhs type ‛Vector a’ does not determine rhs type ‛out’
In the instance declaration for
‛Method1 (Vector a) Vector_testid out’

该错误是由检查功能依赖项可以做什么的新规则引起的,即 liberal coverage condition (据我所知,这是 coverage condition 使用 -XUndecidableInstances 放松)

一些解决问题的尝试

我试图通过更改 Method1 的定义来解决这个问题。至:
class Method1 cls m func | cls -> m where 
method1 :: cls -> m func

这解决了功能依赖关系的问题,但接下来是一行:
testx x = call (method1 x) $ OneTuple "test"

不再允许,导致编译错误(在 7.6 和 7.7 版本中):
Could not deduce (Method1 cls m func0)
arising from the ambiguity check for ‛testx’
from the context (Method1 cls m func,
Call (m func) (OneTuple [Char] -> s))
bound by the inferred type for ‛testx’:
(Method1 cls m func, Call (m func) (OneTuple [Char] -> s)) =>
cls -> s
at debug.hs:50:1-44
The type variable ‛func0’ is ambiguous
When checking that ‛testx’
has the inferred type ‛forall cls (m :: * -> *) func s.
(Method1 cls m func, Call (m func) (OneTuple [Char] -> s)) =>
cls -> s’
Probable cause: the inferred type is ambiguous

编辑:

使用类型族也无法解决这个问题(据我所知)。如果我们替换 Method1使用以下代码(或类似代码)键入类和实例:
class Method1 cls m | cls -> m where 
type Func cls
method1 :: cls -> m (Func cls)

instance Method1 (Vector a) Vector_testid where
type Func (Vector a) = (t1->t1)
method1 = (Vector_testid . testid)

我们会得到明显的错误 Not in scope: type variable ‛t1’ ,因为类型族不允许使用类型,它不会出现在类型表达式的 LHS 上。

最后一个问题

我怎样才能使这个想法在 GHC 7.7 下工作?我知道新的 liberal coverage condition允许 GHC 开发人员在类型检查方面取得一些进展,但它应该以某种方式将在 GHC 7.6 中工作的想法移植到从不编译器版本。

(不强制我的 DSL 用户引入任何进一步的类型 - 到目前为止的所有内容,如类型类实例,我正在使用 Template Haskell 生成)

最佳答案

这不是 GHC 7.7 中的错误。当 GHC 允许实例时,这是一个长期存在的错误
这违反了功能依赖关系。幸运的是,这个问题似乎终于得到了解决。 GHC 7.7 发出的错误消息非常详细,指出了您的实例的问题 Method1 (Vector a) Vector_testid out .记忆泛函的含义
依赖关系。给定

  class C a b | a -> b

因此,如果类型 a , bb1是这样的 C a bC a b1两者都成立, b 一定是真的和 b1是相同的。让我们看看你的实例:
  Method1 (Vector a) Vector_testid (t1->t1)

如果我们有类型 bb1满足 Method1 (Vector Int) Vector_testid (b->b)Method1 (Vector a) Vector_testid (b1->b1) , 一点也不暗示 bb1必须相同。因此,您的实例格式不正确。 GHC 7.6 及之前接受该程序的事实是 GHC 中的一个众所周知的错误(大约每年都在讨论)。

您似乎正在尝试定义类似
 Method1 (Vector a) Vector_testid (forall t. t -> t)

唉,这种语法是不允许的,尽管存在许多工作轮次。例如,其中一个涉及 Apply 类(例如,参见 HList 论文)。更简单的方法如下
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE FunctionalDependencies #-}

-- import Data.Tuple.OneTuple
newtype OneTuple x = OneTuple x deriving Show

------------------------------
-- data types
------------------------------
data Vector a = Vector {x :: a, y :: a, z :: a} deriving (Show)

-- testx x = call (method1 x) $ OneTuple "test"
testx x = call x Method1 $ OneTuple "test"

-- associate methods to classes
class Methods cls m x y | cls m x -> y where
call :: cls -> m -> x -> y

instance Methods (Vector a) Method1 x x where
call self _ x = x

data Method1 = Method1 -- method label

关于haskell - GHC 7.7 中引入的自由覆盖条件破坏了 GHC 7.6 中有效的代码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20778588/

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