2013-07-08 12 views
7

Poniższy kod nie kompiluje:lista indeksowanie z Control.Lens wymaga monoid ograniczenie

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

podając ten błąd

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' 

zakładając, że nie ma sensu być MyType monoid, w jaki sposób mogę uzyskać obiektyw (lub Traversal, czy cokolwiek jest najbardziej odpowiednie - nie jestem pewien rozróżnień), który pozwala mi uzyskać dostęp do tego zagnieżdżonego pola? Najlepiej z możliwością odczytu i aktualizacji.

+1

[Pytanie] (http://stackoverflow.com/q/13434568/712548) (i moja odpowiedź) może również mieć znaczenie tutaj. – shachaf

Odpowiedz

9

Ponieważ ix n może zawieść (np. n >= length list) potrzebny jest czysty sposób na niepowodzenie. Oczywistą awarią wyboru jest element mempty z Monoid. Pytanie, które natychmiast powstaje, to: jeśli twój typ nie może być Monoidem, to w jaki sposób chciałbyś, aby ten kod zawiódł?

Proponuję użyć ^? zamiast ^., a tym samym ponowne Monoid nazwie Maybe:

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

Jako mała uwaga użytą tutaj instancją 'Monoid' jest' First a', a nie 'Maybe a' (ponieważ nie mamy wystarczającej hierarchii typów, aby mówić o afinicznych przejściach). – shachaf

+0

Ahh, dzięki shachaf –