1
{-# LANGUAGE Haskell2010 #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeFamilies #-}

class PoC m where
    type Wrapper m :: * -> *
    wrap :: l -> Wrapper m l

我正在使用 haskell-src-exts,我想升级我的 AST 以获得新生成的标签。由于我想以可扩展的方式进行操作,因此我创建了一个类似于上面代码的接口。但是,升级 AST 的代码不起作用。我有以下内容:

upgrade :: forall f m l. (PoC m, Functor f) => f l -> f (Wrapper m l)
upgrade x = fmap (wrap :: l -> Wrapper m l) x

但是无论是否使用ScopedTypeVariables,我都会得到同样的错误:

/tmp/PoC.hs:10:19:
    Could not deduce (Wrapper m ~ Wrapper m0)
    from the context (PoC m, Functor f)
      bound by the type signature for
                 upgrade :: (PoC m, Functor f) => f l -> f (Wrapper m l)
      at /tmp/PoC.hs:9:12-69
    NB: `Wrapper' is a type function, and may not be injective
    The type variable `m0' is ambiguous
    Possible fix: add a type signature that fixes these type variable(s)
    Expected type: l -> Wrapper m0 l
      Actual type: l -> Wrapper m l
    In the first argument of `fmap', namely
      `(wrap :: l -> Wrapper m l)'
    In the expression: fmap (wrap :: l -> Wrapper m l) x
    In an equation for `upgrade':
        upgrade x = fmap (wrap :: l -> Wrapper m l) x

但我不明白 GHC 在哪里绑定 this m0。“可能不是单射的”是这里问题的核心吗?

4

1 回答 1

2

非内射性确实是个问题。注入性将允许 GHC 知道如果f a ~ f b那样a ~ b,但是由于您可以拥有两个PoC m具有相同Wrapper m类型选择的实例,因此很难知道m在您解决了什么之后Wrapper m是什么。

wrap您应该能够通过添加包含m类型参数的输入项来修复它。这可以是一个从不评估的代理参数

data Proxy a = Proxy

class PoC m where
  type Wrapper m :: * -> *
  wrap :: proxy m -> l -> Wrapper m l

instance PoC () where
  type Wrapper () = Maybe
  wrap _ = return

aUnit :: Proxy ()
aUnit = Proxy

upgrade :: (PoC m, Functor f) => proxy m -> f l -> f (Wrapper m l)
upgrade aProxy x = fmap (wrap aProxy) x
于 2013-11-07T14:50:48.870 回答