Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/file/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
File Haskell:编写文本文件并将其解析回原始格式_File_Parsing_Haskell - Fatal编程技术网

File Haskell:编写文本文件并将其解析回原始格式

File Haskell:编写文本文件并将其解析回原始格式,file,parsing,haskell,File,Parsing,Haskell,我有一个格式为[(String,String)]的元组列表,我需要一个函数将列表的内容写入文本文件,然后另一个函数将此文本文件作为相同的元组列表读取。以下是我对保存功能的了解: save :: Table -> IO() save [] = writeFile "database.txt" "" save zs = do { writeFile "database.txt" "" ; sequence_ [appendFile "database.txt" ("("++a++","++b+

我有一个格式为[(String,String)]的元组列表,我需要一个函数将列表的内容写入文本文件,然后另一个函数将此文本文件作为相同的元组列表读取。以下是我对保存功能的了解:

save :: Table -> IO()
save [] = writeFile "database.txt" ""
save zs = do { writeFile "database.txt" "" ; sequence_ [appendFile "database.txt" ("("++a++","++b++")\n") | (a,b) <- zs] }
save::Table->IO()
保存[]=writeFile“database.txt”“”

save zs=do{writeFile“database.txt”“”;sequence_uu[appendFile“database.txt”(“(“++a++”,“++b++”)”)\n”);(a,b当列表中的字符串包含“,”或“)时,当前函数会出现问题因为这样,当您再次尝试读取数据时,就不可能找到字符串的结尾。每当这些字符出现在字符串中时,您需要以某种方式对其进行转义

它更易于使用,更易于将数据转换为字符串,然后再由您自己完成:

save :: Table -> IO ()
save zs = writeFile "database.txt" (show zs)

show
将特殊字符转义,并确保数据的格式可由
read
解析。要加载数据,请将文件读入字符串,并将其传递给
read
,以将其转换为所需的数据结构。

序言中定义

type ShowS = String -> String
class Show a where
    showsPrec :: Int -> a -> ShowS
    show :: a -> String
    showList :: [a] -> ShowS

type ReadS a = String -> [(a, String)]
class Read a where
    readsPrec :: Int -> ReadS a
    readList :: ReadS [a]
read :: (Read a) => String -> a
简而言之,这些是Haskell中的标准“序列化”方法。
show::(show a)=>a->String
可以将
show
的任何实例转换为字符串,
read::(read a)=>String->a
可以将字符串转换为
read
的任何实例(或引发异常)

标准库中的大多数内置类型和数据结构都定义了
Show
Read
实例;如果您是从它们组成部分,那么您的类型也定义了
Show
Read
实例

type Table = [(String, String)]

load :: (Read a) => FilePath -> IO a
load f = do s <- readFile f
            return (read s)

save :: (Show a) => a -> FilePath -> IO ()
save x f = writeFile f (show x)
有时这是不可能的,您必须定义自己的实例

instance Show Table where
    showsPrec p x = ...
instance Read Table where
    readsPrec p x = ...

但是这不应该是常见的。

show
/
read
方法可以很好地工作,我也使用它,但只适用于较小的值。对于较大、更复杂的值,读取将非常缓慢

此人为示例演示了
读取的不良性能:

data RevList a = (RevList a) :< a | Nil
  deriving (Show, Read)

ghci> read "(((((((((((((((Nil)))))))))))))))" :: RevList Int
data RevList a=(RevList a):读取“(((((((((((((((((((((((((((((((((((()))))))))))”::RevList Int
另外,
read
将无法读取一些有效的Haskell表达式,尤其是使用中缀构造函数的表达式(就像
:对于派生二进制,我想到了。也就是说,在这个简单的例子中,为RevList编写更智能的读取和显示实例是完全可能的,我同意OP应该坚持使用simple,直到可伸缩性成为一个问题。
data RevList a = (RevList a) :< a | Nil
  deriving (Show, Read)

ghci> read "(((((((((((((((Nil)))))))))))))))" :: RevList Int