Haskell 文件I/O不产生输出的困难

Haskell 文件I/O不产生输出的困难,haskell,Haskell,我正在学习Haskell,我正在尝试编写一些代码,这些代码只是读取一个文件,并使用line函数创建一个行列表。例如,我有一个名为data.txt的文件,其中包含以下行: this is line one another line and the final line 下面是我试图用来将这些数据读入列表并打印到屏幕上的代码: import System.IO import Control.Monad main = do let list = [] han

我正在学习Haskell,我正在尝试编写一些代码,这些代码只是读取一个文件,并使用
line
函数创建一个行列表。例如,我有一个名为
data.txt
的文件,其中包含以下行:

this is line one
another line
and the final line
下面是我试图用来将这些数据读入列表并打印到屏幕上的代码:

import System.IO  
import Control.Monad

main = do  
        let list = []
        handle <- openFile "data.txt" ReadMode
        contents <- hGetContents handle
        let myLines = lines contents
            list = listLines myLines
        print list
        hClose handle   

listLines :: [String] -> [String]
listLines = map read

有人能帮我理解我的代码有什么问题吗?谢谢。

hGetContents句柄
将句柄的内容读入字符串。要将所述字符串转换为行列表,您确实需要在换行符上拆分它。您不需要处理
读取
——您只需要字符串。所以您只需要
line::String->[String]
。此外,您的代码似乎表明您在“有必要地思考”,在阅读之前“初始化”
list
。试着做一些类似的事情

main = do 
  handle <- openFile "data.txt" ReadMode
  contents <- hGetContents handle 
  let list = lines contents
  print list
  hClose handle

重述一下这里发生的事情:“data.txt”被读取,其全部内容可用作
contents::String
。您希望将此字符串转换为一个字符串列表,每行一个,即
行内容的确切内容。

正如您可能注意到的,错误消息告诉您
读取有问题,因此让我们重点关注该问题

正如我在评论中所说,
read
接受某个数据类型的值的字符串表示,尝试解析它并返回该值。一些例子:

read "3.14"    :: Double ≡ 3.14    :: Double
read "'a'"     :: Char   ≡ 'a'     :: Char
read "[1,2,3]" :: [Int]  ≡ [1,2,3] :: [Int]
一些非示例:

read "3.14"    :: Double ≡ 3.14    :: Double
read "'a'"     :: Char   ≡ 'a'     :: Char
read "[1,2,3]" :: [Int]  ≡ [1,2,3] :: [Int]
read "[1,2," :: [Int] ≡ error "*** Exception: Prelude.read: no parse"
read "abc"   :: Int   ≡ error "*** Exception: Prelude.read: no parse"
当您尝试使用
String
版本的
read
(即
read::String)时会发生什么情况→ 字符串

Haskell表示的
字符串
(例如,当您在GHCi中计算返回
字符串
的内容时)由一系列包含在
“…”引号中的字符组成。当然,如果要显示某些特殊字符(如换行符),则必须将转义版本放在其中(在本例中为
\n

还记得我写的
read
需要值的字符串表示吗?在您的情况下,
read
正好需要这种字符串格式。当然,它要做的第一件事就是匹配开场白。由于您的第一行不是以
开头,
read
会抱怨并使程序崩溃

read“hello”::String
失败的方式与
read“1”失败的方式相同:[Int]
失败;
1
无法单独解析,因为
Int
s-
read
希望字符串以左括号开始


您可能也听说过
show
,它与
read
相反(但意义非常松散)。根据经验,如果您想
读取
a值
x
,则字符串表示形式
read
应该类似
show x


如果要将文件内容更改为以下内容

"this is line one"
"another line"
"and the final line"
您的代码可以正常工作,并生成以下输入:

["this is line one","another line","and the final line"]
如果您不想更改
.txt
文件,只需删除
list=listLines myLines
并执行
打印myLines
。但是,当您运行该程序时,您将得到

["this is line one","another line","and the final line"]
再说一遍,那有什么问题

print=putStrLn∘ show
show
显示某事物的列表时的默认行为(例如,对于某些
a
;除了得到特殊处理的
Char
)是生成字符串
[firstElement,secondElement…lastElement]
。如您所见,如果要避免使用
[…]
,必须将
[String]
重新合并在一起

还有一个漂亮的函数叫做
unlines
,它是
的逆函数。还要注意,
print
首先调用
show
,但我们不希望这样(我们已经得到了想要的字符串)!所以我们使用
putStrLn
,我们完成了。最终版本:

main = do  
    handle <- openFile "data.txt" ReadMode
    contents <- hGetContents handle
    let myLines = lines contents
    putStrLn (unlines myLines)
    hClose handle
main=do

处理您希望
列表行
做什么?问题是,
字符串→ 字符串
版本的
读取
需要Haskell字符串格式(即原始字符串,如
“Hello\\\”world\\”
,然后将其转换为
Hello“world”
)。如果您只想打印从文件中获得的内容,请完全删除
list=listLines myLines
。我希望
listLines
获取一个字符串列表并返回一个字符串列表。嗯,我真的不明白原始字符串与我的代码有什么关系?您能进一步解释吗?您和中的是同一个人吗?
read
支持设置为获取某个数据类型的字符串表示并将其转换为该类型的值≡ 42
读“[1,2]”:[Int]≡ [1,2]
。什么是已经是字符串的东西的字符串表示形式?好吧,你可以使用字符串(例如
hello world
),添加引号,以转义形式显示特殊字符(即换行符)→ <代码>\n
→ <代码>\“
等等)。您希望Haskell代码以这种形式读取字符串;但由于明显的原因,这失败了。请注意,这并不能解决他在代码中遇到的问题。哦,对不起,我一定是误读了。希望他仍然可以从中提取有用的内容,所以我会让它挂在那里。(编辑:是的,我知道这是关于误解的。
阅读。
。哦,好吧……如果这是常见的礼仪,我会删除答案)没有必要这么做。你有很多有用的东西。哈斯凯勒是好人,他们不会因此而否决你(我希望):)是的,请不要删除。这非常有帮助!哦,为了让您有所期待,这可以写成一行:
readFile“data.txt”>=putStrLn
main = do  
    handle <- openFile "data.txt" ReadMode
    contents <- hGetContents handle
    let myLines = lines contents
    putStrLn (unlines myLines)
    hClose handle