Parsing 为什么Haskell';s类型系统在使用readFile时有问题吗?

Parsing 为什么Haskell';s类型系统在使用readFile时有问题吗?,parsing,haskell,types,readfile,Parsing,Haskell,Types,Readfile,我对Haskell的打字系统有一些问题 情况: 下面的程序在命令行上获取文件名列表 对于每个文件名,使用函数readFile 每个文件的内容都被传递到inputParser(来自Parsec库) 休息并不那么重要 主要问题在于功能读取模块 do表达式的前两个语句在Haskell的类型系统中无效 问题是[String]与IO String与[Char]与 函数parse应该接受一个字符串,但是当它得到它时,它突然想要一个IO字符串(作为同一个参数),否则它想要一个字符串 我想要什么: 读取每个

我对Haskell的打字系统有一些问题

情况:

  • 下面的程序在命令行上获取文件名列表
  • 对于每个文件名,使用函数
    readFile
  • 每个文件的内容都被传递到
    inputParser
    (来自Parsec库)
  • 休息并不那么重要
  • 主要问题在于功能
    读取模块
  • do
    表达式的前两个语句在Haskell的类型系统中无效
  • 问题是
    [String]
    IO String
    [Char]
  • 函数
    parse
    应该接受一个
    字符串
    ,但是当它得到它时,它突然想要一个
    IO字符串
    (作为同一个参数),否则它想要一个
    字符串
我想要什么:

  • 读取每个文件的内容
  • 将该内容作为第三个参数传递给
    parse
    函数
  • 代码如下:

    module Main where
    
    import System.IO
    import System.Environment
    import Text.ParserCombinators.Parsec
    import InputParser
    import Data
    
    usage :: IO ()
    usage = putStrLn "Usage: x file file file option"
    
    parse_modules :: String -> [Char] -> Either ParseError [Module]
    parse_modules filename input = parse inputParser filename input
    
    read_modules :: [String] -> [Module]
    read_modules [] = []::[Module]
    read_modules (filename:rest) =
      do
        content <- readFile filename -- HERE is the problem
        modules <- case parse_modules filename content of -- HERE is problem too
          Left error -> do
            putStr "parse error at "
            print error
          Right out -> out ++ (read_modules rest)
        return modules
    
    use :: [String] -> IO ()
    use args =
      do
        init <- last args
        filenames <- take (length args - 1) args
        modules <- read_modules filenames
        return ()
    
    main :: IO ()
    main = do args <- getArgs
              if length args < 2
                then usage
                else use args
    
    modulemain其中
    导入系统.IO
    导入系统。环境
    导入Text.ParserCombinators.Parsec
    导入输入解析器
    导入数据
    用法::IO()
    用法=putStrLn“用法:x文件选项”
    parse_modules::String->[Char]->ParseError[Module]
    parse_modules filename input=parse inputParser filename input
    读取模块::[String]->[Module]
    读取模块[]=[]::[模块]
    读取模块(文件名:rest)=
    做
    内容输出++(读取模块rest)
    返回模块
    用法::[String]->IO()
    使用args=
    做
    这是错误的

    read_modules :: [String] -> [Module]
    
    应该是

    read_modules :: [String] -> IO [Module]
    
    这并不是您需要解决的全部问题,但它会让您继续前进。

    这是错误的

    read_modules :: [String] -> [Module]
    
    应该是

    read_modules :: [String] -> IO [Module]
    

    这并不是您需要解决的全部问题,但它会帮助您解决问题。

    首先,由于您的函数
    读取模块执行I/O,因此它必须返回类型为
    IO
    的内容。这意味着您必须更改函数中的许多内容:

    read_modules :: [String] -> IO [Module]
    read_modules [] = return []
    read_modules (filename:rest) =
      do
        content <- readFile filename -- HERE is the problem
        modules <- case parse_modules filename content of -- HERE is problem too
          Left error -> do
            putStr "parse error at "
            print error
          Right out -> do 
            more <- read_modules rest
            return (out ++ more)
        return modules
    
  • 空箱子必须使用
    return
  • case表达式中的
    Right
    分支必须使用do表示法
  • 当递归调用自身时,函数必须在do表示法中这样做
  • 这里有一个(希望是)您的
    read\u模块的固定版本
    函数:

    read_modules :: [String] -> IO [Module]
    read_modules [] = return []
    read_modules (filename:rest) =
      do
        content <- readFile filename -- HERE is the problem
        modules <- case parse_modules filename content of -- HERE is problem too
          Left error -> do
            putStr "parse error at "
            print error
          Right out -> do 
            more <- read_modules rest
            return (out ++ more)
        return modules
    
    read_模块::[String]->IO[Module]
    读取模块[]=返回[]
    读取模块(文件名:rest)=
    做
    知足
    
    更多首先,由于您的函数
    read\u模块执行I/O,它必须返回
    IO
    类型的内容。这意味着您必须更改函数中的许多内容:

    read_modules :: [String] -> IO [Module]
    read_modules [] = return []
    read_modules (filename:rest) =
      do
        content <- readFile filename -- HERE is the problem
        modules <- case parse_modules filename content of -- HERE is problem too
          Left error -> do
            putStr "parse error at "
            print error
          Right out -> do 
            more <- read_modules rest
            return (out ++ more)
        return modules
    
  • 空箱子必须使用
    return
  • case表达式中的
    Right
    分支必须使用do表示法
  • 当递归调用自身时,函数必须在do表示法中这样做
  • 这里有一个(希望是)您的
    read\u模块的固定版本
    函数:

    read_modules :: [String] -> IO [Module]
    read_modules [] = return []
    read_modules (filename:rest) =
      do
        content <- readFile filename -- HERE is the problem
        modules <- case parse_modules filename content of -- HERE is problem too
          Left error -> do
            putStr "parse error at "
            print error
          Right out -> do 
            more <- read_modules rest
            return (out ++ more)
        return modules
    
    read_模块::[String]->IO[Module]
    读取模块[]=返回[]
    读取模块(文件名:rest)=
    做
    知足
    
    更多以下是导致您所说的不太重要的另一个错误的原因:

    use :: [String] -> IO ()
    use args =
      do
        init <- last args
    
    看起来你在其他几个地方也犯了同样的错误,不仅仅是那一行。当您只想在函数中创建一个临时变量时,必须像这样以不同的方式对待一元值和非一元值,这对于初学这门语言的人来说是一件容易混淆的事情


    顺便说一下,
    init
    是标准库中函数的名称,因此您可能需要使用不同的变量名。

    以下是导致您所说的其他不太重要的错误的原因:

    use :: [String] -> IO ()
    use args =
      do
        init <- last args
    
    看起来你在其他几个地方也犯了同样的错误,不仅仅是那一行。当您只想在函数中创建一个临时变量时,必须像这样以不同的方式对待一元值和非一元值,这对于初学这门语言的人来说是一件容易混淆的事情


    顺便说一句,
    init
    是标准库中的函数名,因此您可能需要使用不同的变量名。

    您的答案并不完全是我想听到的,但在我阅读了更多关于monad的内容以及在
    IO
    中涉及简单函数时,它可能会有所帮助(目前)不过,如果你考虑一下
    ,作为我之前评论的一个警告,那肯定是过于简单化了,所以不要太直截了当。你的答案并不完全是我想听到的,但在我读了更多关于monad的内容之后,当谈到
    IO
    中的简单函数时,它可能会有所帮助(现在)但是,如果你考虑一下
    ,作为对我之前评论的一个警告,这绝对是一个过于简单化的说法,所以不要太直截了当。谢谢你提到IO。那是个大错误。谢谢你提到IO。这是最大的错误。