2013-07-08 8 views
7

Der folgende Code nicht kompiliert:Indizierungsliste mit Control.Lens erfordert Monoid Einschränkung

{-# LANGUAGE TemplateHaskell #-} 

import Control.Lens 

data MyType = MyType Int 
data Outer = Outer { _inners :: [ Inner ] } 
data Inner = Inner { _val :: MyType } 

$(makeLenses ''Outer) 
$(makeLenses ''Inner) 

i1 = Inner (MyType 1) 
i2 = Inner (MyType 2) 

o = Outer [i1, i2] 

x = o ^. inners . ix 0 . val 

diesem Fehler geben

Toy.hs:17:23: 
No instance for (Data.Monoid.Monoid MyType) 
    arising from a use of `ix' 
Possible fix: 
    add an instance declaration for (Data.Monoid.Monoid MyType) 
In the first argument of `(.)', namely `ix 0' 
In the second argument of `(.)', namely `ix 0 . val' 
In the second argument of `(^.)', namely `inners . ix 0 . val' 

davon aus, dass es keinen Sinn macht, für MyType a zu sein Monoid, wie kann ich ein Objektiv (oder Traversal, oder was auch immer am besten geeignet ist - ich bin mir nicht sicher über die Unterschiede), die mir Zugang zu diesem verschachtelten Feld ermöglicht? Vorzugsweise mit der Fähigkeit, sowohl zu lesen als auch zu aktualisieren.

+1

[Diese Frage] (http://stackoverflow.com/q/13434568/712548) (und meine Antwort) könnte auch hier relevant sein. – shachaf

Antwort

9

Da ix n kann fehlschlagen (ex: n >= length list) Sie brauchen einen sauberen Weg zum Scheitern. Der saubere Fehler der Wahl ist das mempty Element von Monoid. Die Frage, die sich sofort stellt, ist, ob Ihr Typ nicht ein Monoid sein kann. Wie könnte es dann sein, dass dieser Code versagt?

Ich schlage vor, Sie verwenden ^? statt ^., wodurch die Wiederverwendung Monoid namens Maybe:

*Main> o ^? inners . ix 2 . val 
Nothing 
*Main> o ^? inners . ix 0 . val 
Just (MyType 1) 
+2

Als kleine Anmerkung ist die hier verwendete 'Monoid'-Instanz' Erstes a', nicht 'Vielleichta' (da wir nicht genügend Typklassenhierarchie haben, um über affine Durchläufe zu sprechen). – shachaf

+0

Ahh, danke Shachaf –