File Haskell:编写文本文件并将其解析回原始格式
我有一个格式为[(String,String)]的元组列表,我需要一个函数将列表的内容写入文本文件,然后另一个函数将此文本文件作为相同的元组列表读取。以下是我对保存功能的了解: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+
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