我正在玩一个可扩展的记录库,我想编写一个函数field
,它可以作为Lens
或Traversal
运行,具体取决于是否Symbol
或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
习语。我可以提供{
entry: {
app: './app.js',
concatenated: ['es5-shim', 'es5-shim/es5-sham', 'es6-shim',
'./vendor/polyfills.js']
},
output: {
filename: '[name].js'
}
函数来执行我想要的操作,但如果可能的话,我更愿意重载名称[c_name, c.pi for (c_name, c) in prob.constraints.items()]
。你会如何解决这类家庭的限制?
答案 0 :(得分:4)
镜头 已经是遍历,只有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签名。