我正在从XMonad.Actions.WindowMenu中插入xmonad-contrib模块,试图使其可配置。
我很难理解以下几点:
在原码中有一个类似于:
windowMenu :: X ()
windowMenu = withFocused $ \w -> do
tags <- asks (workspaces . config)
-- ...了解那里发生了什么最好的方法是什么?换句话说,在什么环境下评估整个tags <- asks (workspaces . config)?
我提出这个问题的原因是,当我试图在不同的功能中重构它时:
defaultActs :: [(String, X ())]
defaultActs = do
tags <- asks (workspaces . config)
[ ("A: " ++ tag, return ()) | tag <- tags]它因一个错误而爆炸:
• No instance for (MonadReader XConf [])
arising from a use of ‘asks’
• In a stmt of a 'do' block: tags <- asks (workspaces .
In the expression:
do tags <- asks (workspaces . config)
[("A: " ++ tag, return ()) | tag <- tags]
In an equation for ‘defaultActs’:
defaultActs
= do tags <- asks (workspaces . config)
[("A: " ++ tag, return ()) | tag <- tags]编辑后添加:
我理解这一声明的类型:
ghci> :t asks (workspaces . config)
asks (workspaces . config) :: MonadReader XConf m => m [String]
ghci> :t withFocused
withFocused :: (Window -> X ()) -> X ()但它破裂的原因仍然是个谜。
发布于 2020-04-03 20:22:29
最简单的方法是让windowMenu和defaultActions都在X monad中操作,后者已经有了适当的MonadReader实例。所以:
defaultActions :: X [(String, X ())]
defaultActions = do
tags <- asks (workspaces . config)
return ([ ("Cancel menu", return ())
, ("Close" , kill)
, ("Maximize" , withFocused $ \w -> sendMessage $ maximizeRestore w)
, ("Minimize" , withFocused $ \w -> minimizeWindow w)
] ++
[ ("Move to " ++ tag, windows $ W.shift tag) | tag <- tags ])
windowMenu :: X ()
windowMenu = withFocused $ \w -> do
acts <- defaultActions
Rectangle x y wh ht <- getSize w
Rectangle sx sy swh sht <- gets $ screenRect . W.screenDetail . W.current . windowset
let originFractX = (fi x - fi sx + fi wh / 2) / fi swh
originFractY = (fi y - fi sy + fi ht / 2) / fi sht
gsConfig = (buildDefaultGSConfig colorizer)
{ gs_originFractX = originFractX
, gs_originFractY = originFractY }
runSelectedAction gsConfig acts另一个答案中的恶作剧使windowMenu'成为参数化的高阶函数.如果您确实希望创建一个windowMenu',使您能够对操作列表进行参数化,请直接这样做:
windowMenu' :: [(String, X ())] -> X ()
windowMenu' acts = withFocused $ \w -> do
Rectangle x y wh ht <- getSize w
Rectangle sx sy swh sht <- gets $ screenRect . W.screenDetail . W.current . windowset
let originFractX = (fi x - fi sx + fi wh / 2) / fi swh
originFractY = (fi y - fi sy + fi ht / 2) / fi sht
gsConfig = (buildDefaultGSConfig colorizer)
{ gs_originFractX = originFractX
, gs_originFractY = originFractY }
runSelectedAction gsConfig acts在这种情况下,您可以运行defaultActions并使用(>>=) (或更多的do符号)将其结果传递给windowMenu':
windowMenu :: X ()
windowMenu = defaultActions >>= windowMenu'
-- OR
windowMenu = do
acts <- defaultActions
windowMenu' acts发布于 2020-04-03 14:16:48
好吧,多亏了杜普拉德的回答,我才弄明白了:
defaultActions :: XConf -> [(String, X ())]
defaultActions = do
tags <- asks (workspaces . config)
return ([ ("Cancel menu", return ())
, ("Close" , kill)
, ("Maximize" , withFocused $ \w -> sendMessage $ maximizeRestore w)
, ("Minimize" , withFocused $ \w -> minimizeWindow w)
] ++
[ ("Move to " ++ tag, windows $ W.shift tag) | tag <- tags ])
windowMenu' :: (XConf -> [(String, X ())]) -> X ()
windowMenu' actions = withFocused $ \w -> do
acts <- asks actions
Rectangle x y wh ht <- getSize w
Rectangle sx sy swh sht <- gets $ screenRect . W.screenDetail . W.current . windowset
let originFractX = (fi x - fi sx + fi wh / 2) / fi swh
originFractY = (fi y - fi sy + fi ht / 2) / fi sht
gsConfig = (buildDefaultGSConfig colorizer)
{ gs_originFractX = originFractX
, gs_originFractY = originFractY }
runSelectedAction gsConfig acts
-- now it composes well, and I can pass in my own `actions` to `windowMenu`
windowMenu = windowMenu' defaultActions顺便说一句,我无法使它作为X [String]类型工作(不知道为什么),但上面的解决方案似乎运行得很好。也许这不是最好的(不确定),但它带我去我想去的地方。
发布于 2020-04-02 21:27:53
不看任何文档,我们就知道了这一点:这是在withFocused所需要的任何类型的do-表示法的上下文中。它显然以一个函数作为参数,该函数必须返回某种类型的一元值。这个do表示法块的值必须具有相同的类型。它当然没有[(String, X ())]类型。(好吧,好吧,它可以,因为[a]是一个单曲,但这种类型似乎不太可能是withFocused期望的结果)。
您可以通过查看文档来找出它的类型。
withFocused :: (Window -> X ()) -> X ()因为我们的do-表示法在第一个参数lambda的返回值中,所以它必须有一种X ()类型。因此,
asks (workspaces . config) :: X t对于一些t,我们也可以通过查找workspaces的类型来知道。<-以通常的方式将t值绑定到名称tags。
https://stackoverflow.com/questions/61001342
复制相似问题