我正在项目中尝试可扩展记录(我正在使用行类型库),但是当我想以特定方式修改记录中的某些内容时遇到了问题,该返回非常有关重叠实例和不可推论类型的可怕错误。
我想表达的是一个函数,该函数获取包含特定标签类型对的记录,并可以修改该类型。但是当我尝试使用该功能时,会弹出可怕的错误。
我已将错误减少至以下示例。特别是启用IncoherentInstances
(Could not deduce: (Rec.Modify "x" [Double] r .! "x") ~ [Double]
)之后的错误对我来说似乎很奇怪,因为它在那里立即说记录包含"x" :-> [Double]
。
我尝试避免将Rec.Modify
与f2 :: forall r. (HasType aes a r) => Rec r -> Rec (r .- aes .+ aes .== b)
一起使用,但这会导致类似的错误。
我很乐意得到一些帮助,以弄清我做错了什么,以及如何进行类似的工作。
{-# LANGUAGE DataKinds, OverloadedLabels, TypeOperators, RankNTypes,
RecordWildCards, NoMonomorphismRestriction #-}
module GoG.Temp where
import Data.Row
import qualified Data.Row.Records as Rec
type Scale' aes a = Scale aes a a
data Scale aes a b = Scale
-- f1 works great
-- f2 results in very scary errormessages
{ f1 :: forall r. (HasType aes a r) => Rec r -> Rec r
-- What I'd like to express is a function that gets a record containing a
-- specific label-type pair, and may modify that type. But when I try to
-- use that function, the scary errors pop up
, f2 :: forall r. (HasType aes a r) => Rec r -> Rec (Rec.Modify aes b r)
-- ... other fields
}
data Scales = Scales { _xScale :: Scale' "x" [Double] }
extractFromRecord :: (HasType "x" [Double] r, HasType "y" [Double] r)
=> Rec r -> ()
extractFromRecord = undefined
render :: (HasType "x" [Double] r, HasType "y" [Double] r)
=> Scales -> Rec r -> ()
-- If you replace f2 with f1 it works fine, but f2 results in the error
render Scales{..} r = extractFromRecord $ f2 _xScale r
这会导致以下错误:
• Overlapping instances for HasType
"x" [Double] (Rec.Modify "x" [Double] r)
arising from a use of ‘extractFromRecord’
Matching instances:
instance forall k (r :: Row
k) (l :: ghc-prim-0.5.3:GHC.Types.Symbol) (a :: k).
((r .! l) ≈ a) =>
HasType l a r
-- Defined in ‘Data.Row.Internal’
There exists a (perhaps superclass) match:
from the context: (HasType "x" [Double] r, HasType "y" [Double] r)
bound by the type signature for:
render :: forall (r :: Row *).
(HasType "x" [Double] r, HasType "y" [Double] r) =>
Scales -> Rec r -> ()
at /mnt/d/University/infoafp/afp-gog/src/GoG/Temp.hs:22:1-83
(The choice depends on the instantiation of ‘r’
To pick the first instance above, use IncoherentInstances
when compiling the other instance declarations)
• In the expression: extractFromRecord $ f2 _xScale r
In an equation for ‘render’:
render Scales {..} r = extractFromRecord $ f2 _xScale r
|
23 | render Scales{..} r = extractFromRecord $ f2 _xScale r
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
或者如果我们按照建议启用IncoherentInstances,则执行以下操作:
• Could not deduce: (Rec.Modify "x" [Double] r .! "x") ~ [Double]
arising from a use of ‘extractFromRecord’
from the context: (HasType "x" [Double] r, HasType "y" [Double] r)
bound by the type signature for:
render :: forall (r :: Row *).
(HasType "x" [Double] r, HasType "y" [Double] r) =>
Scales -> Rec r -> ()
at /mnt/d/University/infoafp/afp-gog/src/GoG/Temp.hs:23:1-83
• In the expression: extractFromRecord $ f2 _xScale r
In an equation for ‘render’:
render Scales {..} r = extractFromRecord $ f2 _xScale r
• Relevant bindings include
r :: Rec r
(bound at /mnt/d/University/infoafp/afp-gog/src/GoG/Temp.hs:24:19)
render :: Scales -> Rec r -> ()
(bound at /mnt/d/University/infoafp/afp-gog/src/GoG/Temp.hs:24:1)
|
24 | render Scales{..} r = extractFromRecord $ f2 _xScale r
|
答案 0 :(得分:2)
可怕的消息基本上无关紧要。这个简化的示例将HasType
替换为(.!)
,并说明了这个问题,我认为您已经在上面发现了该问题:
{-# LANGUAGE DataKinds, FlexibleContexts, TypeOperators, GADTs #-}
module MyRow where
import Data.Row
import qualified Data.Row.Records as Rec
f2 :: ((r .! "x") ~ Double) => Rec r -> Rec (Rec.Modify "x" Double r)
f2 = undefined
extract :: ((r .! "x") ~ Double) => Rec r -> ()
extract = undefined
render :: ((r .! "x") ~ Double) => Rec r -> ()
render r = extract $ f2 r
此代码导致无法从(Modify "x" Double r .! "x") ~ Double
推论(r .! "x") ~ Double
的错误。这可能是“显然”正确的事实,但这并不意味着GHC可以证明这一点。
很高兴被证明是错误的,但是我认为您将被迫添加所需的显式约束。在您的原始示例中,以下类型签名(GHC可以自行推断出该类型签名)似乎起作用:
render ::
( HasType "x" [Double] r
, HasType "x" [Double] (Rec.Modify "x" [Double] r)
, HasType "y" [Double] (Rec.Modify "x" [Double] r)
) => Scales -> Rec r -> ()
render Scales{..} r = extractFromRecord $ f2 _xScale r
除了您在示例中启用的其他扩展程序之外,我还必须打开FlexibleContexts
和GADTs
。