Haskell 中作为整数的命令行参数

Command line arguments as Ints in Haskell

我有一个 Haskell 程序,它从命令行接受 2 或 3 Ints:

-- test.hs

main :: IO ()
main = do
    args <- fmap (read . head) getArgs
    case args of
        [x,y,a] -> doGeneration x y a
        [x,y]   -> doGeneration x y 10
        _       -> usage

然而,当我 运行 它带有参数时:

$ ./test 100 200
divide: Prelude.read: no parse

为什么?

getArgs :: IO [String] returns 一个 String 的列表,通过取头部然后 args 然后它将 read 该项目。

然而,您从未指定它应该读取什么,因为您在 case … of … 子句中使用 args[x,y,a][x, y],它会尝试读取它作为数字的 list(数字的类型由 doGeneration 签名指定。这意味着您应该将其写为:

$ ./test <strong>[100,200]</strong>

不过我觉得这样做意义不大,你可以将解析部分重写为:

main :: IO ()
main = do
    args <- fmap <strong>(map read)</strong> getArgs
    case args of
        [x,y,a] -> doGeneration x y a
        [x,y]   -> doGeneration x y 10
        _       -> usage

这意味着它将read每个参数单独,并用解析的项目构造一个列表,然后我们可以对程序参数的解析部分进行模式匹配。在那种情况下,我们仍然可以使用:

$ ./test <strong>100 200</strong>

您的 运行 代码等同于

     ....
     case (read "100") of 
         [x,y,a :: Int] -> doGeneration x y a
         [x,y   :: Int] -> doGeneration x y 10
     ....

但是将字符串 "100" 读取为 Int 的列表是不可能的,a.k.a。 “没有解析”。这就是为什么。

Int 来自 doGeneration 的签名,您没有包含。但它必须是 Num,因为您可以互换使用 a10

学习 Haskell 时,最好在 do 块中使用更多变量而不是 fmap。它减轻了认知负担,让您更清楚地了解正在发生的事情:

main :: IO ()
main = do
    args <- getArgs           -- getArgs :: IO [String]
                              -- args    ::    [String]
    let arg1 = head args      -- arg1    ::     String
        val1 = read arg1
    case val1 of
        [x,y,a] -> doGeneration x y a
        [x,y]   -> doGeneration x y 10
        _       -> usage