我正在尝试使用自由单子和镜头(lens)进行编程,使用自由单子来创建自己的IO单子版本:
data MyIO next
= LogMsg String next
| GetInput (String -> next)
deriving (Functor)
我将其堆叠在状态单子之上,如下所示:FreeT MyIO (State GameState) a
其中GameState
为:
data GameState = GameState { _players :: [PlayerState] }
现在,我想要的是一种从GameState
上下文中“放大”到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
中移除列表方面并使用正常的镜头,那么代码就可以工作了。有关如何编写此函数的任何想法吗?
StateT GameState (Free MyIO) a
是否更方便?如果你后面想要将Free MyIO
替换为IO
,那么这是通常的做法,因为IO
没有变换器版本。 - bheklilrMonoid
。如果您只需将zoomPlayer
的类型签名添加Monoid a =>
,那么您就可以了。当然,这会限制您可以返回的内容,但除非您想编写更多代码,否则必须这样做。 - bheklilra
是一个打字错误;实际上应该是a1
。对于造成的混淆我感到非常抱歉。看起来FreeF
是期望成为单子的东西,但我没有办法为它编写一个实例。也许我可以暂时将其包装在列表中,然后再解包。 - Pubby