Haskell,I need to create something like ATM function, stored multiple list in .txt file and retrieve the record

StackOverflow https://stackoverflow.com/questions/13109248

  •  14-07-2021
  •  | 
  •  

문제

Im new in haskell, i need some help with this program. First, i store three accounts into a input.txt, so inside the file will got something like these ["1","steven","4000","12345"]["2","Marcus","5000","123456"]["3","Ivan","7000","12345"]There got 3 variables inside the account which are ID,name,balance and password. what i want to do is:

  1. When the user type the password, the program will compare the password in the list with the password that user type and finally show the particular record

  2. When the user want to transfer the money to another user. first insert the ID, second type the amount of money and finally the first account will reduce the money and the second account will increase the money.

  3. The problem i face is how can i read a single account in order to compare, withdraw and transfer. Is there a better way to do it?

Thanks

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"
도움이 되었습니까?

해결책

I think you should dive straight into properly structured data. First, define some data types to help you solve the problem.

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

You might choose different types if you like. This lets you define functions like

sameID :: ID -> Account -> Bool
sameID anID account = idno account == anID

Notice how the data label idno is also a handy function Account -> ID. We should use some sample data for testing:

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

We can use this to test functions (and deduce that Barney has no clue whatsoever about password security or financial management).

Now you need to decide whether to use Data.Map to store your accounts using their IDs, or a list. Lists are easier to read from a file, but Maps are easier to do finding. So either do:

type Accounts = [Account]

Or use maps:

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

Either way you'll need

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

If you're using a Map, you need to find it. Either browse the documentation - a good plan in any case, or use the hoogle search engine to find it. If you're not sure, you can hoogle for Map ID Account -> Maybe Account and whilst it will warn you it doesn't know about ID or Account, the function you need is there! You'd be better off searching for Map id account -> Maybe account so it knows it can use a general function.

If you're using lists, you'll need to filter the list with a function that gives you true when the ID matches and false otherwise: sameID will help.

You'll also need

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

but far more useful will be

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

If you're using Maps, that will be easy, but if you're using lists, you'll need to to map a function like

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

You can define

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

and functions like

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

Using the idea in changePassword and the function balance, you should be able to write

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

Then you can write

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

hint: use changeBalance (+ amount) and changeBalance (subtract amount).

Finally you'll need

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

I couldn't resist telling you that one because it's a lovely example of function composition.

If you're finding it hard to use the Maybe Account stuff, ignore it until the end, just like we're ignoring file IO till the end. Functions like fmap and >>= are handy when working with Maybe. Look them up, or ditch the Maybe altogether for now and use hard errors. (Eg ! in Map gives errors instead of Nothing.) Maybe is better than runtime errors, but maybe you'll get away with errors for now.

There's some gluing together to do, then some file input/output to do. For the file input/output, it would be simplest to use read and show on your Accounts.

You don't have to do it this way - this is just one approach. (Well, two, if you count list vs map as two approaches.) Have fun!

다른 팁

Indeed, all the problem boils down to your 3rd question. What you are looking for is a data structure allowing you to map user names to user accounts. I suggest looking at the Data.Map container type and see how you can use it.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top