定义泛型实例时触发单态限制

Monomorphism restriction triggered when generic instance defined

考虑以下几点:

{-# LANGUAGE TypeFamilies, FlexibleContexts, GADTs, MultiParamTypeClasses #-}

type family F r

class (Functor t) => T t r where
  fromScalar :: r -> t r

data Foo t r where
  Foo :: t (F r) -> Foo t r
  Scalar :: r -> Foo t r

toF :: r -> F r
toF = undefined

convert :: (T t (F r))
  => Foo t r -> Foo t r
convert (Scalar c) = 
  let fromScalar' = fromScalar
  in Foo $ fromScalar' $ toF c

此代码使用 GHC 7.8.4 编译。

当我为 T 添加通用实例时(需要 FlexibleInstances):

instance (Functor t, Num r) => T t r

GHC 抱怨:

Could not deduce (Num (F r)) arising from a use of ‘fromScalar’
    from the context (T t (F r))
      bound by the type signature for
                 convert :: (T t (F r)) => Foo t r -> Foo t r
      at Main.hs:(17,12)-(18,23)
    In the expression: fromScalar
    In an equation for ‘fromScalar'’: fromScalar' = fromScalar
    In the expression:
      let fromScalar' = fromScalar in Foo $ fromScalar' $ toF c

我记得 this question,但似乎有一些关键差异。首先也是最重要的是,GHC 不会在审理前提出投诉。其次,我没有RankNTypes,这似乎是该问题的核心问题。最后,添加 NoMonoLocalBinds 没有帮助。奇怪的是,添加 NoMonomorphismRestriction 确实 将错误消息从抱怨 fromScalar 更改为关于 fromScalar'.

的相同消息

当然可以通过向 fromScalar 添加类型签名并添加 ScopedTypeVariables:

来解决问题
convert :: forall t r . (T t (F r))
  => Foo t r -> Foo t r
convert (Scalar c) = 
  let fromScalar' = fromScalar :: F r -> t (F r)
  in Foo $ fromScalar' $ toF c

我愿意承认一些与单态类型有关的古怪东西在这里起作用,即使取消限制没有帮助。我的问题是:为什么添加通用实例会触发限制?更重要的是,为什么 GHC 尝试匹配通用实例而不是使用 T (F r) 约束?这似乎是完全错误的,而且有 this bug.

的味道

这是 GHC 错误 #10338。不幸的是,它看起来不会很快得到解决。