Зачем моему типу данных нужен экземпляр Monoid для использования этого объектива?
Я использую код ниже для записи, которая имеет поле '_scene' типа SceneGraph. Я создал линзы для него, используя makeLenses.
inputGame :: Input -> Game -> Game
inputGame i g = flip execState g $ do
let es = g ^. userInput . events
sg = g ^. scene
userInput .= i
scene .= foldl (flip inputEvent) sg es
inputEvent :: InputEvent -> SceneGraph -> SceneGraph
inputEvent (WindowSizeChangedTo (w,h)) (SceneRoot _ _ sg) = SceneRoot w h sg
inputEvent _ sg = sg
Я получаю ошибку:
No instance for (Monoid SceneGraph) arising from a use of `scene'
Possible fix: add an instance declaration for (Monoid SceneGraph)
In the second argument of `(^.)', namely `scene'
In the expression: g ^. scene
In an equation for `sg': sg = g ^. scene
Но я не понимаю, почему SceneGraph должен быть экземпляром Monoid, чтобы использовать этот объектив.
2 ответа
Вы, вероятно, хотите либо (^?)
, или, может быть (^..)
(неоператорские имена: preview
, toListOf
).
Когда у вас есть Lens
(или Getter
, Iso
, Equality
и т. д.), это всегда относится только к одному пункту. Таким образом, вы можете использовать старый добрый (^.)
(имя неоператора: view
). Когда у вас есть Traversal
(или Fold
, Prism
и т. д.), это может относиться к 0 или более элементам.
Поэтому должен быть способ объединить их, если их больше одного, или значение по умолчанию, если их нет. Это сделано с Monoid
ограничение. toListOf
дает вам список всех значений; preview
дает вам либо Nothing
или же Just
первое значение.
Вы не указали типы ни для одной из используемых вами функций, поэтому я не могу точно сказать, что вы намеревались. Я думаю, что может быть scene
может потерпеть неудачу, потому что вы использовали makeLenses
с типом суммы, который не определяет scene
в каждом слагаемом. В этом случае вы, вероятно, захотите использовать (^?)
и обрабатывать Nothing
дело. Но это может быть что-то еще.
Смотрите также мой ответ на этот вопрос (и этот вопрос со вчерашнего дня! Это, кажется, популярная тема).
Я предполагаю, что вы используете библиотеку объективов Эда Кметта, было бы полезно, если бы вы также опубликовали версию, которую вы используете, и данные об импорте. Также похоже, что в этой библиотеке линз поддерживаются две версии (^.), Одна с Getter, а другая с Fold, версия сгиба требует экземпляра Monoid: (^.):: Monoid r => s -> Сложите s r -> r
Изменить: держу пари, что вы случайно импортировали Control.Lens.Fold