我怎样才能给类型推理引擎一些提示?

时间:2011-10-13 18:55:07

标签: class haskell polymorphism type-inference

在(非常)现代的GHC中,我可以这样写:

{-# LANGUAGE TypeFamilies #-}

-- consider this part "library" code, changeable at will
data Container a = Container
data Element
class Foo a where foo :: a -> Int
instance Element ~ a => Foo (Container a) where foo _ = 0

-- consider this part "client" code; bonus points if it can remain exactly as is
main = print (foo Container)

突出点:

  1. 客户端代码不需要任何其他类型签名。
  2. Container是一个多态值(类型为Container a),已正确地与Container Element同构。
  3. 客户端代码中不需要newtype包装器。
  4. 可能无法声明其最外层类型构造函数为Foo的{​​{1}}的另一个实例。这是我在以下讨论中保留的属性。
  5. 这可以以更向后兼容的方式完成吗?我的第一次尝试看起来像这样:

    Container

    ...这给出了一个错误:

    {-# LANGUAGE FlexibleInstances #-}
    
    data Container a = Container
    data Element
    class Foo a where foo :: a -> Int
    instance Foo (Container Element) where foo _ = 0
    
    main = print (foo Container)
    

    我意识到这个错误可能是因为实例没有使用类型变量作为test.hs:8:15: No instance for (Foo (Container a0)) arising from a use of `foo' Possible fix: add an instance declaration for (Foo (Container a0)) In the first argument of `print', namely `(foo Container)' In the expression: print (foo Container) In an equation for `main': main = print (foo Container) 的参数,所以我也试过了:

    Container

    但这只是将问题推送到{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses, UndecidableInstances #-} data Container a = Container data Element class Foo a where foo :: a -> Int instance Convertible a Element => Foo (Container a) where foo _ = 0 class Convertible a b where -- convert is not necessary in this tiny example, but it would -- be necessary in my not-so-tiny use case convert :: Container a -> Container b instance Convertible a a where convert = id main = print (foo Container) 类型类:

    Convertible

    test.hs:14:19: No instance for (Convertible a0 Element) arising from a use of `foo' Possible fix: add an instance declaration for (Convertible a0 Element) In the first argument of `print', namely `(foo Container)' In the expression: print (foo Container) In an equation for `main': main = print (foo Container) 而不是Convertible Element Element编写实例会产生类似的错误。我最后的尝试是进一步专注:

    Convertible a a

    ......它具有H98的显着优势,但仍然不太有效的显着缺点:

    data Container a = Container
    data Element
    class Foo a where foo :: a -> Int
    instance IsElement a => Foo (Container a) where foo _ = 0
    class IsElement a where
        convert :: a -> Element
    instance IsElement Element where
        convert = id
    
    main = print (foo Container)
    

    所以,问题是:是否有一些类似的实现实现了上面的属性1,2和3,但是不需要类型相等运算符?

    编辑我认为排名2类型可能会有所帮助:

    test.hs:10:19:
        Ambiguous type variable `a0' in the constraint:
          (IsElement a0) arising from a use of `foo'
        Probable fix: add a type signature that fixes these type variable(s)
        In the first argument of `print', namely `(foo Container)'
        In the expression: print (foo Container)
        In an equation for `main': main = print (foo Container)
    

    ......但是,唉,仍然没有骰子:

    {-# LANGUAGE FlexibleInstances, RankNTypes #-}
    
    data Container a = Container
    data Element
    class Foo a where foo :: a -> Int
    instance Foo (forall a. Container a) where foo _ = 0
    
    main = print (foo Container)
    

1 个答案:

答案 0 :(得分:2)

我不明白你在这里要做什么。特别是,当您只希望客户使用Container时,为什么关心Container Element是多态的?

那说,如何为类型类使用不同的类型?

data Container a = Container
data Element

class Foo a where foo :: a x -> Int

instance Foo Container where foo _ = 0

现在,将实例化的Container类型确实无关紧要。

如果这不起作用,我怀疑答案是“不,你不能做到你想要的。”虽然您可以导出container = Container :: Container Element并让客户端代码使用该代码而不是Container

编辑:给定完整的上下文,并且也不可能使用rank-2类型,我可以合理地确定在给定问题约束的情况下没有解决方案。我能想到的最佳解决方法是创建一个新函数xcast :: XConfig a -> XConfig Layout。这样您就可以编写instance Binding (XConfig a -> Foo)