zoom 和 free monads 有困难
Difficulty with zoom and free monads
我正在使用免费的 monad 和 lens,使用免费的 monad 创建我自己的 IO monad 版本:
data MyIO next
= LogMsg String next
| GetInput (String -> next)
deriving (Functor)
我将其堆叠在状态 monad 之上,如下所示:FreeT MyIO (State GameState) a
其中 GameState
是:
data GameState = GameState { _players :: [PlayerState] }
现在,我想要的是一种从 GameState
上下文中 "zoom-into" 一个 PlayerState
的方法。像这样:
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
中删除列表方面并使用普通镜头,那么代码就可以工作了。
关于如何编写这个函数有什么想法吗?
如果您确定永远不会索引到一个不存在的玩家并且不介意一点不安全,您可以使用 unsafeSingular
组合器将 Traversal
变成 Lens
,像这样:
zoomPlayer :: Int -> FreeT MyIO (State PlayerState) a -> FreeT MyIO (State GameState) a
zoomPlayer i prog = hoistFreeT (zoom (players . unsafeSingular (element i))) prog
(此外,也许我会使用 ix
而不是 element
,但这与问题无关。)
我们还可以为永远无限的序列构造安全的索引透镜,例如使用 free
包中的 Cofree
定义的流:
import Control.Lens (Lens', _Wrapped')
import Control.Comonad.Cofree (Cofree, telescoped)
import Data.Functor.Identity
import Control
sureIx :: Int -> Lens' (Cofree Identity a) a
sureIx i = telescoped $ replicate i _Wrapped'
但是一个游戏不可能有无限的玩家。
我正在使用免费的 monad 和 lens,使用免费的 monad 创建我自己的 IO monad 版本:
data MyIO next
= LogMsg String next
| GetInput (String -> next)
deriving (Functor)
我将其堆叠在状态 monad 之上,如下所示:FreeT MyIO (State GameState) a
其中 GameState
是:
data GameState = GameState { _players :: [PlayerState] }
现在,我想要的是一种从 GameState
上下文中 "zoom-into" 一个 PlayerState
的方法。像这样:
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
中删除列表方面并使用普通镜头,那么代码就可以工作了。
关于如何编写这个函数有什么想法吗?
如果您确定永远不会索引到一个不存在的玩家并且不介意一点不安全,您可以使用 unsafeSingular
组合器将 Traversal
变成 Lens
,像这样:
zoomPlayer :: Int -> FreeT MyIO (State PlayerState) a -> FreeT MyIO (State GameState) a
zoomPlayer i prog = hoistFreeT (zoom (players . unsafeSingular (element i))) prog
(此外,也许我会使用 ix
而不是 element
,但这与问题无关。)
我们还可以为永远无限的序列构造安全的索引透镜,例如使用 free
包中的 Cofree
定义的流:
import Control.Lens (Lens', _Wrapped')
import Control.Comonad.Cofree (Cofree, telescoped)
import Data.Functor.Identity
import Control
sureIx :: Int -> Lens' (Cofree Identity a) a
sureIx i = telescoped $ replicate i _Wrapped'
但是一个游戏不可能有无限的玩家。