Для индексации списка с Control.Lens требуется ограничение Monoid

Следующий код не компилируется:

{-# 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 не имеет смысла быть моноидом, как я могу получить линзу (или обход, или что-то более подходящее - я не уверен в различиях), который позволяет мне получить доступ к этому вложенному полю? Желательно с возможностью как читать, так и обновлять.

1 ответ

Решение

Так как ix n может потерпеть неудачу (например: n >= length list) вам нужен чистый способ провалиться. Чистая неудача выбора - это mempty элемент из Monoid, Таким образом, сразу возникает вопрос: если ваш тип не может быть Monoid, то как бы вы хотели, чтобы этот код не работал?

Я предлагаю вам использовать ^? вместо ^.тем самым повторно используя Monoid названный Maybe:

*Main> o ^? inners . ix 2 . val
Nothing
*Main> o ^? inners . ix 0 . val
Just (MyType 1)
Другие вопросы по тегам