文件I/O无法生成输出的困难

tur*_*tle 2 haskell

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

this is line one
another line
and the final line
Run Code Online (Sandbox Code Playgroud)

这是我试图用来将这些数据读入列表并将其打印到屏幕上的代码:

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
Run Code Online (Sandbox Code Playgroud)

生成的代码编译,但不生成任何输出.我得到以下输出:

runhaskell test.hs        
read_file.hs: Prelude.read: no parse
Run Code Online (Sandbox Code Playgroud)

任何人都可以帮我理解我的代码有什么问题吗?谢谢.

Vit*_*tus 8

您可能已经注意到,错误消息告诉您存在问题read,所以让我们关注它.

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

read "3.14"    :: Double ? 3.14    :: Double
read "'a'"     :: Char   ? 'a'     :: Char
read "[1,2,3]" :: [Int]  ? [1,2,3] :: [Int]
Run Code Online (Sandbox Code Playgroud)

一些非例子:

read "[1,2," :: [Int] ? error "*** Exception: Prelude.read: no parse"
read "abc"   :: Int   ? error "*** Exception: Prelude.read: no parse"
Run Code Online (Sandbox Code Playgroud)

当你尝试使用(ie )String版本时会发生什么?readread :: String ? String

Haskell的表示String(例如,当您评估StringGHCi 中返回的内容时)由" ... "引号括起来的一系列字符组成.当然,如果你想显示一些特殊字符(比如换行符),你必须将转义版本放在那里(\n在这种情况下).

还记得我写的时候read需要一个值的字符串表示吗?在你的情况,read希望正是这个字符串格式.当然,它尝试做的第一件事就是匹配开头的报价.由于您的第一行没有开头",read抱怨并崩溃该程序.

read "hello" :: String以失败的方式read "1" :: [Int]失败; 1单独无法解析为Ints 列表- read期望字符串以开括号开头[.


您可能也听说过show,这是相反的(但非常松散)read.根据经验,如果您想要read一个值x,字符串表示形式应该是read这样的show x.


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

"this is line one"
"another line"
"and the final line"
Run Code Online (Sandbox Code Playgroud)

你的代码可以正常工作并产生以下输入:

["this is line one","another line","and the final line"]
Run Code Online (Sandbox Code Playgroud)

如果你不想改变你的.txt文件,只是删除list = listLines myLines和做print myLines.但是,当你运行程序时,你会得到

["this is line one","another line","and the final line"]
Run Code Online (Sandbox Code Playgroud)

再次.那么问题是什么?

print = putStrLn ? show并且show当它涉及show某些事物的列表时(即[a]对于某些事物a;除了Char获得特殊处理之外)的默认行为是产生字符串[ firstElement , secondElement ... lastElement ].如您所见,如果您想避开[ ... ],则必须将它们合并[String]在一起.

有一个漂亮的函数被调用unlines,这是相反的lines.另请注意,首先print调用show,但在这种情况下我们不希望这样(我们已经获得了我们想要的字符串)!所以我们使用putStrLn并完成了.最终版本:

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

我们也可以摆脱不必要的lines ~ unlines和公正的putStrLn contents.

  • 哦,只是让你有所期待,这可以写成一行:`readFile"data.txt">> = putStrLn`. (2认同)