请考虑以下事项:
{-# 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的气味。