gpt4 book ai didi

haskell - 无点镜头创建不进行类型检查

转载 作者:行者123 更新时间:2023-12-04 17:47:25 25 4
gpt4 key购买 nike

在函数中 test ,我遍历一个列表,从它的成员中生成镜头,然后打印一些数据。当我使用有针对性的调用风格时,这会起作用。当我使它无点时,它无法进行类型检查。

为什么会这样,我该如何解决这个问题?

在我看来 GHC 没有保留排名较高的信息 f (在镜头中)是Functor使用 point-free 样式时,但我不太确定。

我正在使用 GHC 7.8.3

{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE TemplateHaskell #-}

import Control.Lens
import Control.Monad
import Data.List
import Data.Maybe

type PlayerHandle = String

data Player = Player { _playerHandle :: PlayerHandle }
makeLenses ''Player

data GameState = GameState { _gamePlayers :: [Player] }
makeLenses ''GameState

type PlayerLens = Lens' GameState Player

getPlayerLens :: PlayerHandle -> PlayerLens
getPlayerLens handle 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


printHandle :: GameState -> PlayerLens -> IO ()
printHandle st playerLens = do
let player = st^.playerLens
print $ player^.playerHandle


test :: GameState -> IO ()
test st = do
let handles = toListOf (gamePlayers.traversed.playerHandle) st
--
-- Works: Pointful
--forM_ handles $ \handle -> printHandle st $ getPlayerLens handle
--
-- Does not work: Point-free
forM_ handles $ printHandle st . getPlayerLens


main :: IO ()
main = test $ GameState [Player "Bob", Player "Joe"]
Test.hs:45:38:
Couldn't match type `(Player -> f0 Player)
-> GameState -> f0 GameState'
with `forall (f :: * -> *).
Functor f =>
(Player -> f Player) -> GameState -> f GameState'
Expected type: PlayerHandle -> PlayerLens
Actual type: PlayerHandle
-> (Player -> f0 Player) -> GameState -> f0 GameState
In the second argument of `(.)', namely `getPlayerLens'
In the second argument of `($)', namely
`printHandle st . getPlayerLens'
Failed, modules loaded: none.

最佳答案

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' ,而不是相反。

第三个选项,可能不是最好的镜头,但通常适用于更高级别的类型,是转动您的 PlayerLensnewtype :
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

关于haskell - 无点镜头创建不进行类型检查,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29203844/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com