Haskell,我需要创建类似ATM功能的东西,在.txt文件中存储多个列表并检索记录

时间:2012-10-28 13:39:07

标签: haskell-platform haskell

我是haskell的新手,我需要一些帮助。 首先,我将三个帐户存储到input.txt中,因此文件内部会出现类似[“1”,“steven”,“4000”,“12345”] [“2”,“Marcus”,“5000”的内容,“123456”] [“3”,“Ivan”,“7000”,“12345”]帐户中有3个变量,分别是ID,名称,余额和密码。我想做的是:

  1. 当用户输入密码时,程序会将列表中的密码与用户输入的密码进行比较,最后显示特定记录

  2. 当用户想要将钱转移给其他用户时。首先插入ID,第二种类型的金额,最后第一个帐户将减少钱,第二个帐户将增加钱。

  3. 我面临的问题是如何阅读单个帐户才能进行比较,撤销和转移。有没有更好的方法呢?

  4. 由于

    import System.IO  
    
    i :: IO()
    i = do
        putStrLn "your ID : " 
        id<-getLine
        putStrLn "your name : "
        name<-getLine
        putStrLn "balance : "
        bal<- getLine
        putStrLn "password : "
        pass<- getLine
        let store2 =  [id]++[name]++[bal]++[pass]
        appendFile "input.txt" (show store2)
    
    huhu ::IO()
    huhu = do
        putStrLn "ID : "
        id<-getLine
        putStrLn "Password : "
        pass<-getLine
        rec <- readFile "input.txt"
        if ("pass" == rec) then
            do
            putStrLn "show information"
        else
            do 
            putStrLn "Wrong password"
    

2 个答案:

答案 0 :(得分:4)

我认为您应该直接深入了解结构合理的数据。 首先,定义一些数据类型以帮助您解决问题。

type ID = Int
data Account = Account {idno::ID, 
                        name :: String, 
                        balance :: Int, 
                        password :: String} deriving (Read,Show)

如果您愿意,可以选择不同的类型。 这允许您定义像

这样的函数
sameID :: ID -> Account -> Bool
sameID anID account = idno account == anID

请注意数据标签idno如何也是一个方便的函数Account -> ID。我们应该使用一些样本数据进行测试:

sampleData = [Account 385634 "Fred" 234 "Iluvw1lm4",
              Account 405382 "Barney" (-23) "pebbles",
              Account 453464 "Wilma" 1432 "c4r3fu1n355 br33d5 pr0sp3r:ty"]

我们可以用它来测试功能(并推断出Barney对密码安全或财务管理没有任何线索)。

现在,您需要决定是否使用Data.Map来使用其ID或列表来存储您的帐户。列表更容易从文件中读取,但地图更容易查找。所以要么:

type Accounts = [Account]

或使用地图:

import qualified Data.Map as Map  -- Put this at the top of the file if so.
type Accounts = Map.Map ID Account

无论哪种方式,你都需要

findUserByID :: Accounts -> ID -> Maybe Account
findUserByID = undefined    -- you can work this out

如果您正在使用地图,则需要找到它。在任何情况下都可以浏览documentation - 一个好的计划,或者使用the hoogle search engine来查找它。如果您不确定,可以使用Map ID Account -> Maybe Account进行搜索,虽然它会警告您它不知道ID或帐户,但您需要的功能就在那里!你最好搜索Map id account -> Maybe account,因此它知道它可以使用一般功能。

如果您正在使用列表,则需要filter列表中的一个函数在ID匹配时为true,否则为false:sameID将有所帮助。

您还需要

updateByID :: ID -> Account -> Accounts -> Accounts
updateByID anId newaccount = undefined   -- you can work this out too

但更有用的是

updateUsingID :: Account -> Accounts -> Accounts
updateUsingID acc = updateByID (idno acc) acc

如果你正在使用地图,这将很容易,但如果你使用的是列表,你需要map这样的功能

onlyChange :: Account -> (Account -> Account)
onlyChange newacc acc | idno acc == idno newacc = newacc
                      | otherwise = acc

您可以定义

showAccount :: Account -> String
showAccount acc = undefined -- use the functions, eg  name acc ++ ....
                            -- or just use show

等功能
changePassword :: String -> Account -> Account
changePassword newpwd acc = acc {password = newpwd}

使用changePassword中的想法和函数balance,您应该可以写

changeBalance :: (Int -> Int) -> Account -> Account
changeBalance = undefined   -- you try

然后你可以写

pay :: Int -> Account -> Account -> (Account,Account)
pay amount fromAcc toAcc = undefined

提示:使用changeBalance (+ amount)changeBalance (subtract amount)

最后你需要

updateTwoUsingID :: (Account,Account) -> Accounts -> Accounts
updateTwoUsingID (new1,new2) = updateUsingID new1 . updateUsingID new2

我无法抗拒告诉你那一个,因为它是功能组合的一个可爱的例子。

如果你发现很难使用Maybe Account的东西,请忽略它直到最后,就像我们忽略文件IO直到最后一样。使用fmap时,>>=Maybe等功能非常方便。查看它们,或者暂时放弃Maybe,并使用硬error s。 (例如Map中的!会给出错误而不是Nothing。)也许比运行时错误更好,但也许你现在可以避免错误。

要做一些粘合,然后做一些文件输入/输出。对于文件输入/输出,最简单的方法是在read上使用showAccounts

你不必这样做 - 这只是一种方法。 (好吧,两个,如果你将列表与地图统计为两种方法。)玩得开心!

答案 1 :(得分:3)

事实上,所有问题都归结为你的第三个问题。您正在寻找的是一种数据结构,允许您用户名映射到用户帐户。我建议查看Data.Map容器类型,看看如何使用它。