2017-05-03 1 views
4

Ich spiele mit einer erweiterbaren Record-Bibliothek, und ich möchte eine Funktion field schreiben, die entweder als Lens oder Traversal basierend darauf funktionieren kann, ob der Symbol Schlüssel in der Liste der Schlüssel ist oder nicht. Die Art Familie gegeben:Typfamilien können keinen RankN-Typ zurückgeben - Workarounds oder Alternativen?

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 

Dieser Code gibt mir eine Fehlermeldung:

/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’ 

Im Idealfall würde ich beide die field Namen wiederverwenden zu können, wie für Linsen und Querungen, als wäre es erlauben Sie

>>> let testMap = empty & field @"foo" .~ 'a' 
>>> :t testMap 
HashRecord '["foo" =: Char] 
>>> testMap ^. field @"foo" 
'a' 
>>> testMap ^. field @"bar" 
Type error 
>>> testMap ^? field @"bar" 
Nothing 

zu schreiben, die lens Idiome gemeinsam folgt. Ich kann eine fieldTraversal Funktion zur Verfügung stellen, die tut, was ich will, aber ich würde lieber den Namen field überladen, wenn möglich. Wie würdest du diese Einschränkung der Typfamilien umgehen?

+0

Mögliches Duplikat [Illegal polymorph oder qualifiziert Typ mit RankNTypes und TypeFamilies] (http://stackoverflow.com/questions/13846284/illegal-polymorphic-or-qualified-type-using-rankntypes-and-typefamilies) –

+0

@ AntalSpector-Zabusky vielleicht verwandt, aber das ist definitiv kein Duplikat. – leftaroundabout

Antwort

4

Eine Linse ist bereits ein Traversal, sein einzigen Rank2 quantifier keinen Gebrauch von der vollen Einschränkung machen (es erfordert lediglich Functor, nicht 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 

Es ist auf der Ebene dieser Einschränkung, dass Sie Ihre Art Familie vorstellen sollen:

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 

Dann field sollte keine LensOrTraversal ergeben, sondern immer eine benutzerdefinierte Rank2-Signatur mit der Einschränkung bestimmt durch die Typenfamilie.

+0

Schön! Wenn wir nur Implikationsbeschränkungen hätten, könnten wir nette Dinge wie "muss zumindest ein' Traversal' sein "ausdrücken. Ich habe vor einiger Zeit nach solchen Ideen gefragt. Haben Sie eine knifflige Art, das Konzept ohne explizite Wörterbuchmanipulation auszudrücken? – dfeuer

+0

Puh, keine Ahnung. Ich vermute, es würde ein bisschen Würmer öffnen, wenn wir versuchen würden, solche Beschränkungen von beliebigen polymorphen Typen zu erhalten. Ist das überhaupt entscheidbar? – leftaroundabout

+0

Schön! Das hat mein Problem gelöst. Jetzt muss ich nur herausfinden, wie man diese Informationen auf der Werteebene behandelt ... – ephrion

Verwandte Themen