2013-07-08 20 views
7

下面的代码无法编译:与Control.Lens索引列表,需要含半幺群约束

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

给这个错误

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' 

假定它没有任何意义的MyType是一个monoid,我怎么能得到一个镜头(或遍历,或任何最合适的 - 我不知道的区别),让我访问此嵌套字段?最好具有读取和更新的能力。

+1

[这个问题](http://stackoverflow.com/q/13434568/712548)(我的回答)也可能与此有关。 – shachaf

回答

9

因为ix n可能会失败(例如:n >= length list)您需要一个干净的方式来失败。选择的干净故障是Monoid中的mempty元素。所以立即出现的问题是,如果你的类型不能是一个Monoid,那么你会如何让这个代码失败?

我建议你使用^?代替^.,从而重用Monoid命名为Maybe

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

作为一个小记录,这里使用的'Monoid'实例是'First a',而不是'Maybe a'(因为我们没有足够的类型层次来讨论仿射遍历)。 – shachaf

+0

啊,谢谢shachaf –