You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

错误原因解析

  1. 类型不匹配:你定义的windowsPresent是XState -> String类型的纯函数,但直接将它与字符串"0"比较是错误的——它本身不是String值,而是需要接收XState参数才能返回String的函数。
  2. 逻辑与操作符误用:&&&是Haskell中用于组合函数的操作符(返回新函数,输入同一参数后返回两个函数的结果元组),而非普通逻辑与操作,逻辑与应使用&&。
  3. 未在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 07:47:40