1

我对 Haskell 的类型系统有一些问题。

情况:

  • 以下程序正在命令行上获取文件名列表
  • 对于每个文件名,使用函数读取其内容readFile
  • 每个文件的内容都传递给inputParser(来自Parsec库)
  • 休息不是那么重要
  • 主要问题在于功能read_modules
  • 表达式的前两个语句do在 Haskell 的类型系统中是无效的
  • [String]问题是vs IO Stringvs [Char]vs ...之间的冲突
  • 函数parse应该接受 aString但是当它得到它时,它IO String突然想要一个(作为相同的参数),否则它想要一个String

我想要什么:

  1. 读取每个文件的内容
  2. 将该内容作为第三个参数传递给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

以下是 GHC 输出的错误:

ghc --make -o x.hs input-parser.hs data.hs
[3 of 3] Compiling Main             ( x.hs, x.o )

x.hs:19:4:
    Couldn't match expected type `IO String'
           against inferred type `[String]'
    In a stmt of a 'do' expression: content <- readFile filename
    In the expression:
        do content <- readFile filename
           modules <- case parse_modules filename content of {
                        Left error -> do ...
                        Right out -> out ++ (read_modules rest) }
           return modules
    In the definition of `read_modules':
        read_modules (filename : rest)
                       = do content <- readFile filename
                            modules <- case parse_modules filename content of {
                                         Left error -> ...
                                         Right out -> out ++ (read_modules rest) }
                            return modules
-- THIS ERROR is somewhat not important
x.hs:30:4:
    Couldn't match expected type `[Char]'
           against inferred type `IO Char'
      Expected type: String
      Inferred type: IO Char
    In a stmt of a 'do' expression: init <- last args
    In the expression:
        do init <- last args
           filenames <- take (length args - 1) args
           modules <- read_modules filenames
           return ()
make: *** [x] Error 1

问题是什么:

  • 我不明白我应该在哪里传递 - 我有点知道我想要什么,但我不明白语法或风格。
  • 我是 Haskell 的新手。
  • Haskell 的类型...

有哪些问题:

  • 如何解决出现的类型问题?
  • 我应该投入parse什么——什么readFile给了我?
  • 类型是否兼容?
  • 不需要某种类型的转换吗?

相关网页链接:

谢谢大家的提示和评论。

4

3 回答 3

4

首先,由于你的函数read_modules 执行 I/O,它必须返回一些 type IO。这意味着您必须更改函数中的许多内容:

  1. 空箱必须使用return
  2. case 表达式中的Right分支必须使用 do-notation
  3. 当递归调用自身时,函数必须在 do-notation 中这样做

这是您的功能的(希望是)固定版本read_modules

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

我还没有测试过它,但我希望它可以帮助你。

于 2009-12-21T19:14:55.807 回答
3

这是错误的。

read_modules :: [String] -> [Module]

应该

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

这不是您需要解决的全部问题,但它会让您继续前进。

于 2009-12-21T19:14:50.643 回答
2

以下是导致您所说的另一个不那么重要的错误的原因:

use :: [String] -> IO ()
use args =
  do
    init <- last args

<-运算符在块do中用于提取包含在 monad(在本例中为IO)中的某些内容,以便您可以使用捕获在其中的实际值。但是,args这里是 type [String], not IO [String],所以你不需要这样做;您已经将参数列表从mainIO中拉出。arg <- getArgs

如果要为do块内的临时变量分配非单值值,请let改用,如下所示:

let x = last args

看起来您在其他几个地方也犯了同样的错误,而不仅仅是那条线。当您只想在函数中创建一个临时变量时,必须像这样以不同的方式对待单子值与非单子值,这对于语言新手来说很容易混淆。

By the way, init is the name of a function in the standard library, so you might want to use a different variable name.

于 2009-12-21T21:33:18.853 回答