首页 文章

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

提问于
浏览
1

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

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

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

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

谢谢

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 回答

  • 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或列表存储您的帐户 . 列表更容易从文件中读取,但 Map 更容易查找 . 所以要么:

    type Accounts = [Account]
    

    或者使用 Map :

    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
    

    如果您使用的是 Map ,则需要找到它 . 在任何情况下都可以浏览documentation - 一个好的计划,或者使用the hoogle search engine来查找它 . 如果你不确定,你可以为 Map ID Account -> Maybe Account 进行搜索,虽然它会警告你它不会更好地搜索 Map id account -> Maybe account 所以它知道它可以使用一般功能 .

    如果你需要're using lists, you'列表中的一个函数在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直到最后 . 使用 Maybe 时, fmap>>= 等函数非常方便 . 查看它们,或者暂时放弃Maybe,并使用硬 error . (例如,Map中的 ! 给出错误而不是Nothing . )也许比运行时错误更好,但也许你现在可以逃避错误 .

    有一些粘合在一起做,然后一些文件输入/输出做 . 对于文件输入/输出,在 Accounts 上使用 readshow 最简单 .

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

  • 3

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

相关问题