使用cassava包,以下编译:
{-# LANGUAGE DeriveGeneric #-}
import Data.Csv
import GHC.Generics
data Foo = Foo { foo :: Int } deriving (Generic)
instance ToNamedRecord Foo
但是,以下情况并非如此:
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DeriveAnyClass #-}
import Data.Csv
import GHC.Generics
data Foo = Foo { foo :: Int } deriving (Generic, ToNamedRecord)
编译器报告:
test.hs:7:50:
No instance for (ToNamedRecord Int)
arising from the first field of ‘Foo’ (type ‘Int’)
Possible fix:
use a standalone 'deriving instance' declaration,
so you can specify the instance context yourself
When deriving the instance for (ToNamedRecord Foo)
这给我留下了两个问题:为什么第二个版本与第一个版本完全相同?为什么编译器希望找到ToNamedRecord Int
的实例?
答案 0 :(得分:15)
将根据相同的规则生成实例上下文 在导出
Eq
时使用(如果类型的类型为*
),或者为...的规则 Functor(如果类型的类型是(* -> *)
)。例如instance C a => C (a,b) where ... data T a b = MkT a (a,b) deriving( C )
deriving
子句将会 产生instance C a => C (T a b) where {}
约束
C a
和C (a,b)
是从数据构造函数参数生成的,但是 后者简化为C a
。
因此,根据Eq
规则,您的deriving
子句会生成......
instance ToNamedRecord Int => ToNamedRecord Foo where
......这与...不一样。
instance ToNamedRecord Foo where
...因为前者仅在范围内有instance ToNamedRecord Int
时有效(在您的情况下似乎不存在)。
但我觉得这个规格有些含糊不清。该示例是否真的会生成该代码,还是应该生成instance (C a, C (a, b)) => instance C (T a b)
并让解算器释放第二个约束?在您的示例中,即使对于具有完全具体类型的字段,它也会产生这样的约束。
我毫不犹豫地称这是一个错误,因为它是Eq
的工作原理,但鉴于DeriveAnyClass
旨在使编写空实例更快,它似乎不直观