在以下代码中,我希望尽可能将g . f
重写为h
。可能有h
个案例没有得到类的实例,但我希望在可能的情况下进行重写。我收到一条错误消息,表明这是可以实现的,但我不确定我需要改变什么。
以下是一些示例代码:
{-# LANGUAGE TypeFamilies #-}
main = return ()
data D a
f :: a -> D a
f = undefined
type family T a
class G a where
g :: D (T a) -> a
class H a where
h :: T a -> a
{-# RULES
"myrule" forall x. g (f x) = h x
#-}
这是错误:
• Could not deduce (H a) arising from a use of ‘h’
from the context: G a
bound by the RULE "myrule" at trickyrewrite.hs:19:3-34
Possible fix: add (H a) to the context of the RULE "myrule"
• In the expression: h x
When checking the transformation rule "myrule"
请注意可能的解决方法: add (H a) to the context of the RULE "myrule"
。这似乎可以完成这项工作,但我不确定如何实际做到这一点。规则中甚至没有提及a
,所以我不确定H a
在没有引用任何内容时如何添加a
会有所帮助。
如果它有任何区别,我控制的唯一代码是类H
。我无法改变G
。我的代码当然比这更复杂,但是如果我能看到一个如何使这个简化示例工作的工作示例,我应该能够计算出我认为的代码。
尝试失败:
我已尝试过@ Alec的建议,但它似乎无法正常工作,重写规则未被触发。这是我尝试过的代码:
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeApplications #-}
module Main where
main = ((g (f (2 :: Int))) :: Char) `seq` return ()
data D a
{-# INLINE [1] f #-}
f :: a -> D a
f = undefined
type family T a
type instance T Char = Int
{-# INLINE [1] g' #-}
g' :: (G a) => D (T a) -> a
g' = undefined
class G a where
g :: D (T a) -> a
g = g'
instance G Char
class H a where
h :: T a -> a
{-# RULES
"myrule" forall (x :: H a => T a). g' (f x) = h @a x
#-}
答案 0 :(得分:4)
通常one can add type signatures to the variables in the forall
。像
{-# RULES "myrule" forall (x :: H a => T a). g (f x) = h x #-}
现在,在这种情况下, 幸运的是,我认为TypeApplications
允许我们告知GHC T
类型a
中的类型变量T a
与x
中的那个:
h
我们不需要启用{-# LANGUAGE TypeFamilies, TypeApplications, AllowAmbiguousTypes #-}
...
{-# RULES "myrule" forall (x :: H a => T a). g (f x) = h @a x #-}
(即使我们依赖它来确保ScopedTypeVariables
是相同的),因为它在重写规则中默认启用。