[英]Why does Haskell's type system have a problem with my use of readFile?
I have some troubles with Haskell's type system.我对 Haskell 的类型系统有一些麻烦。
Situation:情况:
readFile
对于每个文件名,使用函数readFile
读取其内容inputParser
(from Parsec library)每个文件的内容传递给inputParser
(来自Parsec库)read_modules
主要问题在于函数read_modules
do
expression are invalid in Haskell's type system do
表达式的前两个语句在 Haskell 的类型系统中无效[String]
vs IO String
vs [Char]
vs ...问题是[String]
vs IO String
vs [Char]
vs ... 之间的冲突parse
should take a String
but when it gets it, it wants an IO String
suddenly (as the same argument), otherwise it wants a String
函数parse
应该接受一个String
但是当它得到它时,它突然想要一个IO String
(作为相同的参数),否则它想要一个String
What do I want:我想要什么:
parse
function as third argument将该内容作为第三个参数传递给parse
函数Here is the code:这是代码:
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
Here are the errors GHC outputs:以下是 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
What is the problem:有什么问题:
What are the questions:有哪些问题:
parse
- what readFile
gives me?我应该在parse
放入什么 - readFile
给了我什么?Relevant weblinks:相关网页链接:
Thank you all for your hints and comments.谢谢大家的提示和评论。
First of all, since your function read_module
s performs I/O it must return something of type IO
.首先,由于您的函数read_module
s 执行 I/O,它必须返回IO
类型的东西。 That means that you have to change a number of things in your function:这意味着您必须更改函数中的许多内容:
return
空的情况必须使用return
Right
branch in the case expression must use do-notation case 表达式中的Right
分支必须使用 do-notationHere's a (hopefully) fixed version of your read_modules
function:这是您的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
I haven't tested it but I hope it will help you on the way.我还没有测试过,但我希望它能在路上帮助你。
This is wrong.这是错误的。
read_modules :: [String] -> [Module]
Should be应该是
read_modules :: [String] -> IO [Module]
That is not all that you need to fix, but it will get you going.这不是您需要解决的全部问题,但它会让您继续前进。
Here's what's causing the other error that you said was less important:以下是导致您所说的另一个不太重要的错误的原因:
use :: [String] -> IO ()
use args =
do
init <- last args
The <-
operator is used within a do
block to extract something contained in a monad (in this case, IO
) so that you can work with the actual value trapped inside. <-
运算符用于do
块中以提取包含在 monad(在本例中为IO
)中的内容,以便您可以使用困在其中的实际值。 But, args
here is of type [String]
, not IO [String]
, so you don't need to do that;但是,这里的args
是[String]
类型,而不是IO [String]
,所以你不需要这样做; you already pulled the argument list out of IO
with arg <- getArgs
in main.您已经使用arg <- getArgs
在 main 中从IO
提取了参数列表。
If you want to assign a non-monadic value to a temporary variable inside a do
block, use let
instead, like this:如果你想给do
块内的临时变量分配一个非 monadic 值,请改用let
,如下所示:
let x = last args
It looks like you're making the same mistake in several other places as well, not just that line.看起来您在其他几个地方也犯了同样的错误,而不仅仅是那一行。 Having to treat monadic vs. non-monadic values differently like that, when you just want to make a temporary variable inside your function, is an easy thing to get confused about for someone new to the language.当你只想在你的函数中创建一个临时变量时,必须以不同的方式对待 monadic 和非 monadic 值,对于语言的新手来说很容易混淆。
By the way, init
is the name of a function in the standard library, so you might want to use a different variable name.顺便说一下, init
是标准库中函数的名称,因此您可能需要使用不同的变量名称。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.