Я отвод вокруг с бесплатными монадами и объективом, с помощью бесплатной монады, чтобы создать свою собственную версию монады IO:Трудности с зумом и свободными монадами
data MyIO next
= LogMsg String next
| GetInput (String -> next)
deriving (Functor)
Я штабелирование это на вершине государственной монады как так: FreeT MyIO (State GameState) a
где GameState
является:
data GameState = GameState { _players :: [PlayerState] }
Теперь, что я хотел бы иметь способ «зум-в» а PlayerState
из GameState
контекста. Что-то вроде этого:
zoomPlayer :: Int -> FreeT MyIO (State PlayerState) a -> FreeT MyIO (State GameState) a
zoomPlayer i prog = hoistFreeT (zoom (players . element i)) prog
Но я получаю эту ошибку:
No instance for (Data.Monoid.Monoid a1)
arising from a use of ‘_head’
Эта ошибка кажется, связанная с тем, что players . element i
является обходом; если я удалю список из _players
и использую обычный объектив, тогда код работает.
Любые идеи о том, как написать эту функцию?
Не будет ли проще иметь 'StateT GameState (Free MyIO) a'? Если вы хотите позже поменять «Free MyIO» на «IO», тогда это будет обычным способом, так как нет трансформаторной версии 'IO'. – bheklilr
Кроме того, проблема связана с тем, что индексирование списка не является безопасной. Библиотека объективов хочет, чтобы вы возвращали тип, который можно использовать по умолчанию, а стандартным классом для этого является «Monoid». Если вы просто добавите 'Monoid a =>' в подпись типа 'zoomPlayer', тогда вы будете установлены. Это, конечно, ограничивает то, что вы можете вернуть, но вам придется, если вы не хотите писать больше кода. – bheklilr
@bheklir Плохо, «ошибка» была опечаткой; это было фактически 'a1'. Прошу прощения за путаницу. Кажется, что 'FreeF' - это то, что он ожидает быть моноидом, но у меня нет способа написать экземпляр для этого. Возможно, я мог бы временно обернуть его в список, а затем развернуть. – Pubby