在多义词中将一元值转换为 IO



我正在尝试使用 Haskell 中的webdriverpolysemy构建一个自动化的功能测试套件。我已经定义了适当的效果并将它们解释为网络驱动程序WD monad,但现在我陷入了困境。

我有一个类型为Member BrowserMaster r => Sem r ()的值,其中BrowserMaster是我的自定义功能。

这是解释器:

runBrowserMaster :: Members [Embed WD.WD, Embed IO] r => Sem (BrowserMaster ': r) a -> Sem r a
runBrowserMaster = interpret $ case
ClickElement bmSelector ->
let action = (WD.findElem (bmSelectoToSelector bmSelector) >>= WD.click :: WD.WD ())
in embed action
{- ... -}

现在我想知道如何将Embed WD.WD效果转换为Embed IO,以便我最终只得到一个。

我试图制作一个口译员:

runWebDriver :: Member (Embed IO) r => Sem (Embed WD.WD ': r) a -> Sem r a
runWebDriver = interpret $
a -> embed $ runSession chromeConfig . finallyClose $ do
setImplicitWait 60000
setWindowSize (1024, 768)
unEmbed a

(这里runSession chromeConfig . finallyClose是一个WD a -> IO a(

它确实有效,但它似乎为每个命令启动一个新的浏览器会话,而不是只启动一次,在里面做所有事情并关闭。

我有一种直觉,它必须与资源的获取和释放有关,但我就是无法理解这一点才能将它们放在一起。

请记住,每次执行BrowserMaster效果的动作时,都会执行每个解释器。因此,每次它运行runWebDriver解释器时,这解释了它创建、运行和关闭会话的原因。

我认为您要做的是创建/删除会话一次,然后在此会话中执行整个代码。 另外,由于WD已经是IO的包装器,我认为没有必要嵌入这两种效果。

我不熟悉您的代码或webdriver库,但我认为这将是大致如下的内容:

main :: IO ()
main = runSession chromeConfig . finallyClose $ do
setImplicitWait 60000
setWindowSize (1024, 768)
runM . runBrowserMaster $ myBusinessCode
runBrowserMaster :: Member (Embed WD.WD) r => Sem (BrowserMaster ': r) a -> Sem r a
runBrowserMaster = interpret $ case
ClickElement bmSelector ->
let action = (WD.findElem (bmSelectoToSelector bmSelector) >>= WD.click :: WD.WD ())
in embed action
{- ... -}

注意:如果您需要在解释器中运行一些IO代码,请使用liftIO使其成为WD操作,例如liftIO $ putStrLn "Hello world".

PS:我建议将runBrowserMaster解释器重命名为类似browserMasterToWD,因为它更好地表示它的作用:根据WD操作来解释BrowserMaster效果。

最新更新