使用Control.Lens索引列表需要Monoid约束。

9
下面的代码无法编译:
{-# 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 不是一个单子类型,我该如何获取一个 Lens(或 Traversal,或者任何最适合的东西 - 我不确定区别)来访问这个嵌套字段?最好能够读取和更新。

1
这个问题(以及我的回答)可能也与此相关。 - shachaf
1个回答

11
因为ix n可能失败(例如:n >= length list),所以您需要一种清晰的出错方式。选择清晰的失败方式是来自Monoidmempty元素。因此,立即出现的问题是,如果您的类型不能是Monoid,那么您希望此代码如何失败?
我建议您使用^?而不是^.,从而重用名为MaybeMonoid
*Main> o ^? inners . ix 2 . val
Nothing
*Main> o ^? inners . ix 0 . val
Just (MyType 1)

2
作为一个小提示,这里使用的Monoid实例是First a,而不是Maybe a(因为我们没有足够的类型类层次结构来谈论仿射遍历)。 - shachaf

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接