【问题标题】:Weird return in HaskellHaskell 的奇怪回归
【发布时间】:2011-08-15 04:12:47
【问题描述】:
checkstring :: [String] -> Int -> [String]
checkstring p n = do    z <- doesFileExist (p !! n)
    if z
    then p
    else error $ "'" ++ (p !! n) ++ "' file path does not exist"

它通过查看“n”来检查字符串中的元素(因此如果 n = 2,它将检查列表中的第二个字符串是否存在)然后查看它是否存在。如果确实存在,它将返回原始字符串列表,如果不存在,则会出错。为什么要这样做? :

Couldn't match expected type `[t0]' with actual type `IO Bool'
    In the return type of a call of `doesFileExist'
    In a stmt of a 'do' expression: z <- doesFileExist (p !! n)

【问题讨论】:

标签: haskell haskell-platform


【解决方案1】:

doesFileExist 的类型是String -&gt; IO Bool。如果你的程序想知道一个文件是否存在,它必须与文件系统交互,这是一个 IO 动作。如果你想让你的 checkString 函数做到这一点,它还必须有某种基于 IO 的类型。例如,我认为这样的事情会起作用,虽然我还没有尝试过:

checkstring :: [String] -> Int -> IO [String]
checkstring p n = do    z <- doesFileExist (p !! n)
    if z
    then return p
    else error $ "'" ++ (p !! n) ++ "' file path does not exist"

【讨论】:

  • 如何将其更改为基于 IO 的类型?
【解决方案2】:

补充 MatrixFrog 在他的回答中提到的内容。如果您查看您的函数签名,即[String] -&gt; Int -&gt; [String],它表明该函数是一个纯函数并且不涉及任何副作用,而在您的函数体中,您使用的是doesFileExist,其签名为String -&gt; IO Bool,其中IO 的存在表明它是一个不纯的函数,即它涉及一些 IO。在haskell中,不纯函数和纯函数之间有严格的区分,事实上,如果你的函数调用了其他一些不纯的函数,那么你的函数也是不纯的。因此,在您的情况下,您的函数 checkString 需要不纯,这可以通过使其返回 IO [String] 来完成,这就是 MatrixFrog 在他的回答中提到的。

另一方面,我建议您可以使函数类似于:
checkString :: String -&gt; IO (Maybe String),因为您的函数不需要整个字符串列表,因为它只需要列表中的特定字符串做它的工作,而不是抛出错误,你可以使用 Maybe 来检测错误。 这只是一个建议,但它也取决于您的函数的使用方式。

【讨论】:

    【解决方案3】:

    我认为问题在于您的类型签名强制 do 块假定它是其他一些单子。例如,假设您正在使用 list monad。然后,你可以写

    myFcn :: [String] -> Int -> [String]
    myFcn p n = do
        return (p !! n)
    

    在 list monad 的情况下,return 只是返回单例列表,所以你会得到类似的行为,

    > myFcn ["a", "bc", "d"] 1
    ["bc"]
    

    (我个人的看法是,如果 GHC 可以选择打印出可能导致类型错误的常见错误,那将非常有帮助;我很同情提问者,因为我收到了很多类型错误消息花点时间弄清楚)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-04-08
      • 1970-01-01
      • 1970-01-01
      • 2020-06-25
      • 2020-03-14
      • 2017-02-21
      • 1970-01-01
      • 2015-05-23
      相关资源
      最近更新 更多