【问题标题】:Haskell: Reading from FS to "dynamically" create widgets in taffybarHaskell:从 FS 读取以“动态”在 taffybar 中创建小部件
【发布时间】:2016-04-26 22:33:53
【问题描述】:

我正在尝试使用 taffybar 作为我的状态栏(使用 Dyre 框架,所以配置就是代码)。它有一个可以显示网络接口统计信息的小部件。在默认配置中,此小部件在编译时需要 String。我希望它为每个(非环回)接口动态创建一个小部件。

这是我目前所拥有的:

listNetworkDevices :: IO [String]
listNetworkDevices = fmap (map takeBaseName) $ getDirectoryContents "/sys/class/net/"

filterOutLoopback :: [String] -> [String]
filterOutLoopback = filter (\y -> not (elem y ["", ".", "lo"]))

netDevList :: IO [String]
netDevList = fmap filterOutLoopback listNetworkDevices

...

let nets = fmap (fmap (netMonitorNew 1)) netDevList
    ...
defaultTaffybar defaultTaffybarConfig {
    ...
    endWidgets = [ tray, clock, mem, cpu] ++ nets ++ [ bat ]
}

此时我遇到以下编译器错误:

Couldn't match expected type ‘[IO gtk-0.14.2:Graphics.UI.Gtk.Types.Widget]’
            with actual type ‘IO [IO gtk-0.14.2:Graphics.UI.Gtk.Types.Widget]’

总的来说,这个错误是有道理的,因为我从每个 String 中生成了一个 IO Widget。所以IO [String] 变成了IO [IO Widget]

我不明白如何避免这样做。很明显,我一定是在某个时候出错了,但我看不出在哪里。我什至不知道如何用语言表达这个问题。我会很高兴任何指针!

相关资料:

编辑:完整列表:

import System.Taffybar
import System.Taffybar.Systray
import System.Taffybar.Pager
import System.Taffybar.TaffyPager
import System.Taffybar.SimpleClock
import System.Taffybar.Battery
import System.Taffybar.NetMonitor
import System.Taffybar.Weather
import System.Taffybar.Widgets.PollingBar
import System.Taffybar.Widgets.PollingGraph
import System.Information.Memory
import System.Information.CPU
import System.Directory ( getDirectoryContents )
import System.FilePath ( takeBaseName )
import Control.Monad

memCallback = do
  mi <- parseMeminfo
  return [memoryUsedRatio mi]

cpuCallback = do
  (userLoad, systemLoad, totalLoad) <- cpuLoad
  return [totalLoad, systemLoad]

listNetworkDevices :: IO [String]
listNetworkDevices = fmap (map takeBaseName) $ getDirectoryContents "/sys/class/net/"

filterOutLoopback :: [String] -> [String]
filterOutLoopback = filter (\y -> not (elem y ["", ".", "lo"]))

netDevList :: IO [String]
netDevList = fmap filterOutLoopback listNetworkDevices

myPagerConfig = defaultPagerConfig {}

main = do
  let memCfg = defaultGraphConfig { graphDataColors = [(1, 0, 0, 1)] }
      cpuCfg = defaultGraphConfig { graphDataColors = [ (0, 1, 0, 1)
                                                      , (1, 0, 1, 0.5)
                                                      ]
                                  }
      clock = textClockNew Nothing "<span fgcolor='orange'>%a %b %d %H:%M</span>" 1
      pager = taffyPagerNew myPagerConfig
      mem = pollingGraphNew memCfg 1 memCallback
      cpu = pollingGraphNew cpuCfg 1 cpuCallback
      bat = textBatteryNew "$percentage$% $time$" 1
      tray = systrayNew

      --nets = [ netMonitorNew 1 "wlp0s2" ]
      nets = fmap  (fmap (netMonitorNew 1)) netDevList

  defaultTaffybar defaultTaffybarConfig { startWidgets = [ pager ]
                                        , endWidgets = [ tray, clock, mem, cpu] ++ nets ++ [ bat ]
                                        }

编辑:错误信息:

.config/taffybar/taffybar.hs:
    Couldn't match expected type ‘[IO
                                     gtk-0.14.2:Graphics.UI.Gtk.Types.Widget]’
                with actual type ‘IO [IO gtk-0.14.2:Graphics.UI.Gtk.Types.Widget]’
    In the first argument of ‘(++)’, namely ‘nets’
    In the second argument of ‘(++)’, namely ‘nets ++ [bat]’

【问题讨论】:

  • 能否添加完整的错误消息和引发错误的完整源代码函数。另外我认为您的源代码不正确 - let-statement 在文件中没有意义。
  • @epsilonhalbe:完成。
  • 我没有仔细研究过代码,但我的猜测是 memcallback 或 cpucallback 错误(添加类型签名)或nets= 应该是nets &lt;-
  • 这些部分确实有效。如果您将 nets = 替换为上面一行中已注释掉的版本,则一切都可以编译并且工作正常(也可以与 github.com/travitch/taffybar/blob/master/taffybar.hs.example 进行比较)。除了我只有一个硬编码接口这一明显问题。如果我这样做 nets &lt;- ghc 会抱怨我不在 do 块中的解析错误。

标签: haskell


【解决方案1】:

我没有像往常一样对此进行测试,因为我没有在这台机器上安装 taffybar,但我怀疑以下小改动应该可以帮助您取得进展:

main = do
  let memCfg = defaultGraphConfig { graphDataColors = [(1, 0, 0, 1)] }
      cpuCfg = defaultGraphConfig { graphDataColors = [ (0, 1, 0, 1)
                                                      , (1, 0, 1, 0.5)
                                                      ]
                                  }
      clock = textClockNew Nothing "<span fgcolor='orange'>%a %b %d %H:%M</span>" 1
      pager = taffyPagerNew myPagerConfig
      mem = pollingGraphNew memCfg 1 memCallback
      cpu = pollingGraphNew cpuCfg 1 cpuCallback
      bat = textBatteryNew "$percentage$% $time$" 1
      tray = systrayNew

  -- this line is the only one that changed
  nets <- fmap  (fmap (netMonitorNew 1)) netDevList

  defaultTaffybar defaultTaffybarConfig { startWidgets = [ pager ]
                                        , endWidgets = [ tray, clock, mem, cpu] ++ nets ++ [ bat ]
                                        }

可能还有其他问题,但这应该解决问题中描述的问题。

当然,也可以/应该进行很多风格上的改变;例如,我想我可能会这样写最后两行:

  nets <- netDevList
  defaultTaffybar ... { ..., endWidgets = ... ++ map netMonitorNew nets ++ ... }

【讨论】:

  • 谢谢,这确实解决了问题。您认为您可以用一两句话评论我最初在做什么(错误)吗?我仍在尝试开发语言来讨论 Haskell 代码。
  • @McEnroe 你可能会喜欢 sigfpe 的introduction to IO
猜你喜欢
  • 2016-12-13
  • 2021-09-15
  • 1970-01-01
  • 1970-01-01
  • 2020-09-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多