2013-07-08 15 views
7

Il seguente codice non viene compilato:elenco indicizzazione con Control.Lens richiede Monoide vincolo

{-# 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 

dando questo errore

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' 

supponendo che non ha senso per MyType sia un monoide, come posso ottenere una lente (o traversata, o qualunque cosa sia più appropriata - non sono sicuro delle distinzioni) che mi permette di accedere a questo campo annidato? Preferibilmente con la capacità di leggere e aggiornare.

+1

[Questa domanda] (http://stackoverflow.com/q/13434568/712548) (e la mia risposta) potrebbe essere rilevante anche qui. – shachaf

risposta

9

Perché ix n può non riuscire (ad esempio: n >= length list) è necessario un modo pulito per fallire. Il fallimento pulito di scelta è l'elemento mempty da Monoid. Quindi la domanda che sorge immediatamente è se il tuo tipo non può essere un Monoid, quindi come vorresti che questo codice fallisse?

vi consiglio di utilizzare ^? invece di ^., riutilizzando così l'Monoid nome Maybe:

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

Come piccola nota, l'istanza di 'Monoid' qui usata è' Prima a', non 'Forse a' (poiché non abbiamo abbastanza gerarchia di classi di tipi per parlare di attraversamenti affini). – shachaf

+0

Ah, grazie shachaf –

Problemi correlati