Lens'
是一种排名较高的类型,类型推断非常脆弱,并且基本上仅在所有采用较高排名参数的函数都具有显式签名时才有效。这对于使用无点代码非常糟糕.
等等,没有这样的签名。 (仅有的$
有时有一个特殊的技巧可以解决这个问题。)
The lens
库本身通过确保所有函数都可以解决这个问题use镜头参数没有完全通用的镜头类型,而只有一种表明它们的精确镜头特征的类型use.
在你的情况下,这是printHandle
函数是造成这种情况的罪魁祸首。如果您将其签名更改为更精确,您的代码将会编译
printHandle :: s -> Getting Player s Player -> IO ()
我通过删除原始签名并使用找到了这个签名:t printHandle
.
编辑(并再次编辑以添加ALens'
):如果您认为“治疗比疾病更糟糕”,那么根据您的需要,还有另一种选择,它不需要您更改函数签名,但需要更改does要求你做一些显式转换,就是使用ALens'
改为键入。然后您需要更改两行:
type PlayerLens = ALens' GameState Player
...
printHandle st playerLens = do
let player = st^.cloneLens playerLens
...
ALens'
是一种非更高级别的类型,经过巧妙构造,因此它包含从中提取通用镜头所需的所有信息cloneLens
。但它仍然is镜头的特殊子类型(Functor
刚刚被特别巧妙地选择)所以你只需要显式转换from ALens'
to Lens'
,而不是相反。
第三种选择,对于镜头来说可能不是最好的,但通常适用于更高级别的类型general,就是把你的PlayerLens
into a newtype
:
newtype PlayerLens = PL (Lens' GameState Player)
当然,现在需要在代码中的多个位置进行包装和解包。getPlayerLens
受到特别干扰:
getPlayerLens :: PlayerHandle -> PlayerLens
getPlayerLens handle = PL playerLens
where
playerLens f st = fmap put' get'
where
players = st^.gamePlayers
put' player = let
g p = case p^.playerHandle == handle of
True -> player
False -> p
in set gamePlayers (map g players) st
get' = f $ fromJust $ find (\p -> p^.playerHandle == handle) players