首页 文章

我怎样才能向GHC证明(b~Foo)?

提问于
浏览
2

新问题

我不会假装我知道如何思考或谈论哈斯克尔 . 在伪java-oo-jargon中:

我想要做的是有一个“实现”“接口”的“结构” . 该接口的一部分是一个返回实现另一个接口的对象的函数 .

interface IFiz {}

interface IBuz {
    function IFiz getFiz() 
}

class Foo implements IFiz { ... }
class Bar implements IBuz {
    IFiz fiz = new Foo();
    function getFiz() {
        return fiz;
    }
}

我怎么能在Haskell中做到这一点?我这样做的尝试如下所述 .


旧问题

我怎样才能向GHC证明(b~Foo)?

我对这个问题的理解:

Foo是类型类Fiz的一个实例 .

我希望Bar成为类型Buz的一个实例 .

但是,编译器无法在 punk 方法的实现中推断出(b~Foo) . 但还有什么呢?我尝试使用不推荐的直接方式添加数据约束,以及使用GADT,但似乎都没有工作(我继续得到完全相同的错误 . )

data Foo = Foo Int                                                                                                                                                                                                                           
data Bar = Bar Foo                                                                                                                                                                                                                           

class Fiz a where                                                                                                                                                                                                                            
    funk :: a -> a -- Not important, I just wanted to put something in Fiz                                                                                                                                                                                                                           

class Buz a where                                                                                                                                                                                                                            
    punk :: Fiz b => a -> b                                                                                                                                                                                                                  

instance Fiz Foo where                                                                                                                                                                                                                       
    funk a = a                                                                                                                                                                                                                               

instance Buz Bar where                                                                                                                                                                                                                       
   punk (Bar foo) = foo

Could not deduce (b ~ Foo)
from the context (Fiz b)
  bound by the type signature for punk :: Fiz b => Bar -> b
  at Test.hs:42:5-8
  ‘b’ is a rigid type variable bound by
      the type signature for punk :: Fiz b => Bar -> b at Test.hs:42:5
Relevant bindings include punk :: Bar -> b (bound at Test.hs:42:5)
In the expression: foo
In an equation for ‘punk’: punk (Bar foo) = foo

2 回答

  • 6

    此类型签名:

    class Buz a where
      punk :: Fiz b => a -> b
    

    punk 必须能够返回 b 类型的任何类型的 b ,因为它是 Fiz 的实例 . 所以问题不在于编译器不能推断 FooFiz 的实例,而是返回值不是 Quux ,这是 Fiz 的一个实例 .

    data Quux = Quux 
    
    instance Fiz Quux where
      funk a = a
    

    如果你想让函数类型返回 Fiz 的任何实例,你可以使用ExistentionalQuantification扩展:

    {-# LANGUAGE RankNTypes, ExistentialQuantification #-}   
    data Foo = Foo Int
    data Bar = Bar Foo
    data SomeFiz = forall a . Fiz a => SomeFiz a
    class Fiz a where
      funk :: a -> a
    
    class Buz a where
      punk :: a -> SomeFiz
    
    instance Fiz Foo where
      funk a = a
    
    instance Buz Bar where
      punk (Bar foo) = SomeFiz foo
    

    否则,如果你真的想要实现这个类型类,你只能通过将底部传递给 funk 来实现:

    instance Buz Bar where
      punk _ = funk undefined
    -- or for example:
    instance Buz Bar where
      punk _ = funk (funk undefined)
    

    或者通过修复funk:

    instance Buz Bar where
      punk _ = fix funk
    

    如果你能提供你想要达到的目标的更多细节,也许我会给出更多有用的答案 .

  • 4

    你不能 .

    Buz 表示如果 a 具有 Buz 的实例,那么对于具有 Fiz 实例的 every b ,您可以从 a -> b 提供函数 . Fiz 类在生成 b 时几乎没有任何帮助; funk 只会给你一个 b ,如果你已经 b .

    您可能误解了GHC的错误消息 . 类型推断是双向的 . 在这种情况下, b 来自类 Buzpunk 的签名 . 对于每种类型 b ,它要求 punk 的结果为 b 类型 . Foo 不是所有类型的东西 .

    ‘b’ is a rigid type variable bound by
          the type signature for punk :: Fiz b => Bar -> b at Test.hs:42:5
    

相关问题