【问题标题】:Parsing a CSV list from command line argument in Haskell从 Haskell 中的命令行参数解析 CSV 列表
【发布时间】:2013-11-09 20:02:44
【问题描述】:

我有一个程序需要一些命令行参数。

假设第一个命令行参数是一个逗号分隔值 (CSV) 整数列表。

我想将第一个参数"1,2,4,8,16" 转换为[1,2,4,8,16]。我试图将字符串解析为 Int 列表,但出现编译错误。

Haskell 代码:

import System.Environment
import Data.List
import Text.Regex

main = do
  args <- getArgs

  ints <- if   (length args > 1)
          then (mapM read (splitRegex (mkRegex ",") (args!!1)))
          else [1,3,5] -- defaults
  print (ints)

编译错误:

myProg.hs:10:16:
    Couldn't match expected type `IO' with actual type `[]'
    In the expression: [1, 3, 5]
    In a stmt of a 'do' block:
      ints <- if (length args > 1) then
                  (mapM read (splitRegex (mkRegex ",") (args !! 1)))
              else
                  [1, 3, 5]
    In the expression:
      do { args <- getArgs;
           ints <- if (length args > 1) then
                       (mapM read (splitRegex (mkRegex ",") (args !! 1)))
                   else
                       [1, ....];
           print (ints) }

我不确定这种类型的错误是什么意思。如果有人能向我解释类型错误以及如何修改我的代码以达到预期的结果,我将不胜感激。

【问题讨论】:

  • 我建议使用木薯来解析 CSV 而不是正则表达式。我知道这不是您问题的答案,但可能是适合这项工作的工具。

标签: haskell command-line-arguments haskell-platform


【解决方案1】:

您不想使用&lt;- 定义ints,因为您没有在其中执行 IO 操作。您可以只使用 let 绑定。这也让您可以用普通的map 替换对mapM 的调用。

第一个正确的参数也被索引为 0,而不是像您在 C 中看到的那样为 1。您也可以使用 head 来获得它。

let ints = if   length args >= 1
           then map read (splitRegex (mkRegex ",") (head args))
           else [1, 3, 5]

【讨论】:

    【解决方案2】:

    表达式

    if   (length args > 1)
    then (mapM read (splitRegex (mkRegex ",") (args!!1)))
    else [1,3,5] -- defaults
    

    是错误类型的,因为这两种情况(then,else)的值不重合。 mapM的类型是

    mapM :: Monad m => (a -> m b) -> [a] -> m [b]
    

    所以 then 分支的类型为 m [b] 对于某些 monad m(在本例中为 IO)。然而,else 分支只是一个数字列表。您可以通过编写来修复错误

    return [1,3,5]
    

    对于else情况,使其类型为IO [Int]。

    但这可能不是最好的前进方式。您的 then 分支有问题; read 函数在 IO 中没有返回值,所以这里不适合作为 mapM 的第一个参数。实际上,没有理由在 IO 中进行这种计算,因为 int 的值是作为参数 (args) 的纯函数获得的。我建议在 main 之外实现它,作为具有类型的函数

    extractInts :: [String] -> [Int]
    

    然后您可以像这样将其放入 main 中:

    main = do
      args <- getArgs
      let ints = extractInts args
      print ints
    

    【讨论】:

      猜你喜欢
      • 2012-01-26
      • 1970-01-01
      • 2021-12-07
      • 2013-03-21
      相关资源
      最近更新 更多