【问题标题】:Why is a list of strings suddenly a list of list of strings?为什么字符串列表突然变成字符串列表?
【发布时间】:2015-11-25 13:34:17
【问题描述】:

我有一个函数:

setDisplays :: Char -> [String] -> IO()
setDisplays mode dIds
    | mode == 'l' = chngDispl (head dIds)
    | mode == 'e' = chngDispl (tail dIds)
    where
      chngDispl on = mapM_ (\id -> callProcess "xrandr" ["--output", id, "--auto"]) on

获取带有 xrandr 提供的 Displays id 的字符串列表,看起来像 ["eDP1", "HDMI1"]。该列表通过绑定IO () 传递给setDisplays

getDisplays >>= setDisplays 'e'

现在,我收到以下错误消息: parser.hs:50:37:

    Couldn't match type ‘Char’ with ‘[Char]’
    Expected type: [[String]]
      Actual type: [String]
    In the first argument of ‘head’, namely ‘dIds’
    In the first argument of ‘chngDispl’, namely ‘(head dIds)’
Failed, modules loaded: none.

我不明白。甚至 ghc-mod 都告诉我,第一次提到的名称 dIds 标识 [String],当我在函数调用中使用 ghc-mod 进行类型检查时,它标识 [[[Char]]]。这里发生了什么?

【问题讨论】:

  • type String = [Char]

标签: list haskell types


【解决方案1】:

如果dIds[String],则head 的结果将是String,但chngDispl 期望[String]。这就是为什么编译器认为head 的参数应该是[[String]]

head dIds 包装在一个列表中,错误就会消失。

您通常应避免使用head 并改用模式匹配。你可以像这样重写你的函数:

setDisplays :: Char -> [String] -> IO()
setDisplays mode (id:ids)
    | mode == 'l' = chngDispl [id]
    | mode == 'e' = chngDispl ids
    where
      chngDispl on = mapM_ (\id -> callProcess "xrandr" ["--output", id, "--auto"]) on

请注意,如果列表为空,这将失败(但head 也会失败),您也应该处理这种情况。

【讨论】:

  • ...更好的是,使用模式匹配并摆脱 head。
  • @JanGreve 我添加了一个模式匹配示例。
【解决方案2】:

您在dIds 上使用head 并希望它是[String]。因此,类型推断告诉我们,以这种方式使用的 dId 应该是 [[String]] 类型。

另外,您在下面一行的dIds 上使用tail。类型不匹配。

【讨论】:

  • 另外,head 通常是邪恶的。 (这个问题并不是真正的原因之一,但它也增加了证据。)
  • 第二个。 head 应该重命名为 evilHead 以更清楚地反映它的邪恶:)
猜你喜欢
  • 2022-01-21
  • 2021-07-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-04-09
相关资源
最近更新 更多