XMonad配置问题:如何检测工作区中是否存在窗口
XMonad配置中
changeWorkspaces函数的类型错误与功能实现问题 我在xmonad.hs配置中编写了changeWorkspaces函数,期望实现:当参数z为True且目标工作区存在窗口时,执行notifyWS发送通知。上述代码是我为解决该问题尝试的多种方案之一。我查阅过XMonad.StackSet和XMonad.Operations文档,但难以理解其用法;也曾尝试其中的peek、index、member等函数,甚至查看了它们的源码,但因Haskell知识有限,无法将其转换为可用于判断的布尔值或算术比较条件。当前代码触发类型不匹配错误,具体错误信息如下:
xmonad.hs:223:54: error: • Couldn't match type: [Char] with: XState -> String Expected: XState -> String Actual: String • In the second argument of ‘(/=)’, namely ‘"0"’ In the second argument of ‘(&&&)’, namely ‘windowsPresent /= "0"’ In the first argument of ‘when’, namely ‘(z == True &&& windowsPresent /= "0")’ | 223 | when (z == True &&& windowsPresent /= "0") $ notifyWS i |
完整的相关代码片段如下:
-- // workspace navigation -- mod-[1..9] = Switch to workspace -- mod-shift-[1..9] = Move window to workspace -- mod-control-[1..9] = Move window to workspace and switch to that workspace [ ((modm .|. m, k), changeWorkspaces f i z) | (i, k) <- zip (myWorkspaces) [xK_1 .. xK_9] , (f, m, z) <- [ (W.greedyView, 0, False), (W.shift, shiftMask, True), (\i -> W.greedyView i . W.shift i, controlMask, True) ] ] where changeWorkspaces f i z = do windows $ f i when (z == True && windowsPresent /= "0") $ notifyWS i where notifyWS i = spawn ("notify-send \"hello, workspace: " ++ i ++ "\"") windowsPresent :: XState -> String windowsPresent = show . length . W.index . windowset
错误原因解析
- 类型不匹配:你定义的
windowsPresent是XState -> String类型的纯函数,但直接将它与字符串"0"比较是错误的——它本身不是String值,而是需要接收XState参数才能返回String的函数。 - 逻辑与操作符误用:
&&&是Haskell中用于组合函数的操作符(返回新函数,输入同一参数后返回两个函数的结果元组),而非普通逻辑与操作,逻辑与应使用&&。 - 未在X monad上下文获取状态:要获取当前工作区状态,必须在X monad上下文里通过
gets等函数获取XState,而非直接定义纯函数。
修正后的代码
以下是实现预期功能的正确版本,核心是修改判断逻辑,在X monad上下文里检查目标工作区是否有窗口:
-- // workspace navigation -- mod-[1..9] = Switch to workspace -- mod-shift-[1..9] = Move window to workspace -- mod-control-[1..9] = Move window to workspace and switch to that workspace [ ((modm .|. m, k), changeWorkspaces f i z) | (i, k) <- zip (myWorkspaces) [xK_1 .. xK_9] , (f, m, z) <- [ (W.greedyView, 0, False), (W.shift, shiftMask, True), (\i -> W.greedyView i . W.shift i, controlMask, True) ] ] where changeWorkspaces f i z = do windows $ f i -- 当z为True且目标工作区有窗口时发送通知 when (z && hasWindowsOnWorkspace i) $ notifyWS i where notifyWS i = spawn ("notify-send \"hello, workspace: " ++ i ++ "\"") -- 判断指定工作区是否存在窗口 hasWindowsOnWorkspace wsName = do -- 获取当前的工作区状态StackSet stackSet <- gets windowset -- 查找指定名称的工作区 case W.lookupWorkspace wsName stackSet of -- 找到工作区后,判断其窗口列表是否非空 Just workspace -> return $ not $ null $ W.index workspace -- 找不到工作区则返回False Nothing -> return False
关键说明
- 使用
gets windowset获取当前工作区状态(StackSet类型) - 通过
W.lookupWorkspace根据名称查找目标工作区 - 用
W.index获取工作区的窗口列表,通过null判断是否为空,取反后得到是否有窗口的布尔值 - 布尔值判断无需
z == True,直接写z即可(z本身就是布尔值)
内容的提问来源于stack exchange,提问作者Anapal
相关产品推荐
相关产品推荐

