为类型家族的唱片编写经典镜头?
Writing classy lenses for records with type families?
与Lenses and TypeFamilies and How to derive instances for records with type-families and How to make lenses for records with type-families相关
每次我热情地尝试使用类型族来减少一些样板代码时,我都会把自己编程到一个角落。这是最新的——如何在下面给出的代码片段中为 RecordPoly f
定义镜头?
{-# LANGUAGE TemplateHaskell, DeriveGeneric, MultiParamTypeClasses, FunctionalDependencies, UndecidableInstances, DataKinds #-}
module Try where
import Control.Lens
data PGInt
data PGText
data Selector = Haskell | DB
type family DBField (f :: Selector) hask db where
DBField 'Haskell hask _ = hask
DBField 'DB _ db = db
data RecordPoly f = RecordPoly
{ recFieldA :: !(DBField f Int PGInt)
, recFieldB :: !(DBField f String PGText)
}
class HasFieldA s a | s -> a where fieldA :: Lens' s a
instance HasFieldA (RecordPoly 'Haskell) Int where
fieldA fctor (RecordPoly fa fb) = fmap (\x -> RecordPoly x fb) (fctor fa)
失败并出现以下错误:
• Illegal instance declaration for ‘HasFieldA (RecordPoly f) a’
The liberal coverage condition fails in class ‘HasFieldA’
for functional dependency: ‘s -> a’
Reason: lhs type ‘RecordPoly f’ does not determine rhs type ‘a’
Un-determined variable: a
• In the instance declaration for ‘HasFieldA (RecordPoly f) a’
唯一似乎有效的是以下内容:
instance HasFieldA (RecordPoly 'Haskell) Int where
fieldA fctor (RecordPoly fa fb) = fmap (\x -> RecordPoly x fb) (fctor fa)
这是让它工作的唯一方法吗(从而导致一种新的样板爆炸)?这段代码的类似多态版本如何工作,但当它与类型族一起工作时却不行:
data RecordPoly fa fb = RecordPoly
{ recFieldA :: fa
, recFieldB :: fb
}
class HasFieldA s a | s -> a where fieldA :: Lens' s a
instance HasFieldA (RecordPoly fa fb) fa where
fieldA fctor (RecordPoly fa fb) = fmap (\x -> RecordPoly x fb) (fctor fa)
终于想通了...
instance (fa ~ DBField f Int PGInt) => HasFieldA (RecordPoly f) fa where
fieldA fctor (RecordPoly fa fb) = fmap (\x -> RecordPoly x fb) (fctor fa)
与Lenses and TypeFamilies and How to derive instances for records with type-families and How to make lenses for records with type-families相关
每次我热情地尝试使用类型族来减少一些样板代码时,我都会把自己编程到一个角落。这是最新的——如何在下面给出的代码片段中为 RecordPoly f
定义镜头?
{-# LANGUAGE TemplateHaskell, DeriveGeneric, MultiParamTypeClasses, FunctionalDependencies, UndecidableInstances, DataKinds #-}
module Try where
import Control.Lens
data PGInt
data PGText
data Selector = Haskell | DB
type family DBField (f :: Selector) hask db where
DBField 'Haskell hask _ = hask
DBField 'DB _ db = db
data RecordPoly f = RecordPoly
{ recFieldA :: !(DBField f Int PGInt)
, recFieldB :: !(DBField f String PGText)
}
class HasFieldA s a | s -> a where fieldA :: Lens' s a
instance HasFieldA (RecordPoly 'Haskell) Int where
fieldA fctor (RecordPoly fa fb) = fmap (\x -> RecordPoly x fb) (fctor fa)
失败并出现以下错误:
• Illegal instance declaration for ‘HasFieldA (RecordPoly f) a’
The liberal coverage condition fails in class ‘HasFieldA’
for functional dependency: ‘s -> a’
Reason: lhs type ‘RecordPoly f’ does not determine rhs type ‘a’
Un-determined variable: a
• In the instance declaration for ‘HasFieldA (RecordPoly f) a’
唯一似乎有效的是以下内容:
instance HasFieldA (RecordPoly 'Haskell) Int where
fieldA fctor (RecordPoly fa fb) = fmap (\x -> RecordPoly x fb) (fctor fa)
这是让它工作的唯一方法吗(从而导致一种新的样板爆炸)?这段代码的类似多态版本如何工作,但当它与类型族一起工作时却不行:
data RecordPoly fa fb = RecordPoly
{ recFieldA :: fa
, recFieldB :: fb
}
class HasFieldA s a | s -> a where fieldA :: Lens' s a
instance HasFieldA (RecordPoly fa fb) fa where
fieldA fctor (RecordPoly fa fb) = fmap (\x -> RecordPoly x fb) (fctor fa)
终于想通了...
instance (fa ~ DBField f Int PGInt) => HasFieldA (RecordPoly f) fa where
fieldA fctor (RecordPoly fa fb) = fmap (\x -> RecordPoly x fb) (fctor fa)