haskell - 默认方法中对幻像类型的类约束的编译错误

标签 haskell compiler-errors typeclass phantom-types

这个(有点 absurd 的)模块编译:

{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE ExplicitForAll #-}

module Foo where

class A t where
  f :: forall x m. Monoid x => t m -> m
  f = undefined

instance A [] where
  f = undefined

如果我删除实例的 f 定义,我希望它继承方法默认值并达到相同的效果。
{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE ExplicitForAll #-}

module Foo where

class A t where
  f :: forall x m. Monoid x => t m -> m
  f = undefined

instance A [] where

但是,这不起作用。 GHC 8.0.2 给出了这个错误:
• Could not deduce (Monoid x0)
    arising from a use of ‘Foo.$dmf’
  from the context: Monoid x
    bound by the type signature for:
               f :: Monoid x => [m] -> m
    at src/Foo.hs:10:10-13
  The type variable ‘x0’ is ambiguous
  These potential instances exist:
    instance Monoid a => Monoid (IO a) -- Defined in ‘GHC.Base’
    instance Monoid Ordering -- Defined in ‘GHC.Base’
    instance Monoid a => Monoid (Maybe a) -- Defined in ‘GHC.Base’
    ...plus 7 others
    (use -fprint-potential-instances to see them all)
• In the expression: Foo.$dmf @[]
  In an equation for ‘f’: f = Foo.$dmf @[]
  In the instance declaration for ‘A []’

我不确定如何阅读这个错误,因为我不知道想象中的 x0 在哪里正在插入。为什么第二个示例不编译?

最佳答案

GHC 基本上是将您的代码转换为:

{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE ExplicitForAll #-}

module Foo where

defaultF :: forall t x m. (A t, Monoid x) => t m -> m
defaultF = undefined

class A t where
  f :: forall x m. Monoid x => t m -> m
  f = defaultF @t @x @m

instance A [] where
  f = defaultF @[]

现在,在最后一行,类型变量 x不在范围内,因为我们没有明确的 forall x .即使是,它也不会传递给 defaultF作为显式类型参数。所以,最后一个 defaultF可以在任何幺半群上进行调用,可能是另一个!

对于该调用,推理引擎生成一个新的 x0类型变量,因此类型错误消息:-(

也许 GHC 的实例派生机制应该更新,现在允许模棱两可的类型(这是一件好事,IMO)。

对于更简单的情况,考虑
a :: forall x. Monoid x => Int
a = undefined

b :: forall x. Monoid x => Int
b = a

在 Haskell 中,最后一个调用需要一个明确的类型参数。它可以在像 Agda/Idris/Coq/... 这样的依赖类型语言中正常工作,因为这些(至少在默认情况下)显式传递它们的类型参数。

关于haskell - 默认方法中对幻像类型的类约束的编译错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46350839/

相关文章:

scala - 如何为泛型类型编写 scalaz.IsEmpty 参数

haskell - 如何在 haskell 中为数据类型创建 Read 实例

http - Haskell 中 GET 请求的编码问题

ghc - 使用 foldl', foldr 列出连接

haskell - 如何在不执行括号的情况下定义简单的 RIO LogFunc

Haskell 函数组合题

apache-flex - 类mx.core::DesignLayer could not be found

objective-c - 使用Swift的TFHpple框架进行编译错误

gcc - GCC编译产生此处未声明的 “real.h:53: error: ' SIZEOF_LONG'(不在函数中)”

scala - 类型类中的多个类型参数