我正在使用可扩展的记录库玩,我想编写一个函数field
,该功能可以根据Symbol
密钥是否为Lens
或Traversal
操作在钥匙列表中。给出了类型的家庭:
type family LensOrTraversal key keys s t a b where
LensOrTraversal key '[] s t a b =
Traversal s t a b
LensOrTraversal key (key =: val ': xs) s t a b =
Lens s t a b
LensOrTraversal key (foo =: bar ': xs) s t a b =
LensOrTraversal key xs s t a b
此代码给我一个错误:
/home/matt/Projects/hash-rekt/src/Data/HashRecord/Internal.hs:433:5:
error:
• Illegal polymorphic type: Traversal s t a b
• In the equations for closed type family ‘LensOrTraversal’
In the type family declaration for ‘LensOrTraversal’
理想情况下,我希望能够重复使用镜头和遍历的field
名称,因为它可以允许您写
>>> let testMap = empty & field @"foo" .~ 'a'
>>> :t testMap
HashRecord '["foo" =: Char]
>>> testMap ^. field @"foo"
'a'
>>> testMap ^. field @"bar"
Type error
>>> testMap ^? field @"bar"
Nothing
遵循常见的lens
成语。我可以提供一个可以执行我想要的fieldTraversal
功能,但是如果可能的话,我希望将名称 field
超载。您将如何处理这种类型家庭的限制?
lens 是已经是遍历,只有其rank2量词不使用完整的约束(它仅需要Functor
,而不是Applicative
(。
type Lens s t a b = ∀ f . Functor f => (a -> f b) -> s -> f t
type Traversal s t a b = ∀ f . Applicative f => (a -> f b) -> s -> f t
您应该介绍您的类型家庭的层面:
import GHC.Exts (Constraint)
type family FieldOpticConstraint key keys :: (* -> *) -> Constraint where
FieldOpticConstraint key '[] = Applicative
FieldOpticConstraint key (key =: val ': xs) = Functor
FieldOpticConstraint key (_ ': xs) = FieldOpticConstraint key xs
则field
不应产生LensOrTraversal
,而应始终具有由类型族确定的约束的自定义rank2-签名。