2017-05-03 58 views
4

我正在玩一个可扩展记录库,而且我想要编写一个函数field,根据Symbol密钥是否在密钥列表中,它可以作为LensTraversal运行。该类型的家庭给出:类型系列不能返回RankN类型 - 解决方法或替代方法?

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。你将如何解决这种类型家庭的限制?

+0

[使用RankNTypes和TypeFamilies的非法多态或限定类型]可能重复(http://stackoverflow.com/questions/13846284/illegal-polymorphic-or-qualified-type-using-rankntypes-and-typefamilies) –

+0

@ AntalSpector-Zabusky也许是相关的,但这绝对不是重复的。 – leftaroundabout

回答

4

镜头已经遍历,只有它的秩2量词不使用全约束的(它仅仅需要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,但总是一个自定义的秩2的签名与约束由类型家庭决定。

+0

不错!如果只有我们有暗示约束,我们可以表达漂亮的东西,比如“至少必须是一个”遍历“。后来我问了这样的想法。你有没有明确的字典操作来表达概念的棘手方法? – dfeuer

+0

唷,不知道。我怀疑如果我们试图从任意多态类型获得这样的约束,它会打开一些蠕虫。这是甚至可以决定的吗? – leftaroundabout

+0

不错!这解决了我的问题。现在,我只需要弄清楚如何在价值水平上处理这些信息...... – ephrion