Зачем моему типу данных нужен экземпляр 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

Другие вопросы по тегам