2013-07-08 24 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 –