SO是一场狗屎秀。感谢您的搭车。
Lens'
是一种排名较高的类型,类型推断非常脆弱,并且基本上仅在所有采用较高排名参数的函数都具有显式签名时才有效。这对于使用 .
等没有此类签名的无点代码来说效果非常糟糕。 (只有$
有一个特殊的技巧有时可以解决这个问题。)
lens
库本身通过确保所有使用镜头参数的函数没有完全通用的镜头类型来解决这个问题,而只有一个指示它们使用的精确镜头功能的类型。
就您而言,罪魁祸首是
printHandle
函数。如果您将其签名更改为更精确,您的代码将会编译
printHandle :: s -> Getting Player s Player -> IO ()
我通过删除原始签名并使用
:t printHandle
找到了这个签名。
编辑(并再次编辑以添加
ALens'
):如果您认为“治愈比疾病更糟糕”,那么根据您的需要,可以选择另一个选项,它不需要您更改函数签名,但需要更改功能签名 要求你做一些显式转换,就是使用 ALens'
类型来代替。然后您需要更改两行:
type PlayerLens = ALens' GameState Player
...
printHandle st playerLens = do
let player = st^.cloneLens playerLens
...
ALens'
是一种非更高级别的类型,其构造巧妙,因此它包含使用
cloneLens
从中提取通用镜头所需的所有信息。但它仍然是镜头的特殊子类型(
Functor
刚刚被特别巧妙地选择),所以你只需要显式转换从
ALens'
到
Lens'
,而不是相反。第三种选择,可能不是最好的镜头,但通常适用于
general中的高级类型,是将你的PlayerLens
变成
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