1

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

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

  2. 当用户想要将钱转移给另一个用户时。首先输入ID,第二个输入金额,最后第一个账户减少钱,第二个账户增加钱。

  3. 我面临的问题是如何读取单个帐户以进行比较、提款和转账。有更好的方法吗?

谢谢

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"
4

2 回答 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 还是列表来存储您的帐户。列表更容易从文件中读取,但地图更容易查找。所以要么这样做:

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

如果您使用的是地图,则需要找到它。要么浏览文档——无论如何都是一个好计划,要么使用hoogle 搜索引擎来找到它。如果您不确定,您可以 hoogle for Map ID Account -> Maybe Account,虽然它会警告您它不知道 ID 或 Account,但您需要的功能就在那里!你最好搜索一下,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)and changeBalance (subtract amount)

最后你需要

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

我忍不住要告诉你那个,因为它是函数组合的一个很好的例子。

如果您发现很难使用这些Maybe Account东西,请忽略它直到最后,就像我们忽略文件 IO 直到最后一样。fmap使用和之类的函数>>=非常方便Maybe。查找它们,或者现在完全放弃 Maybe 并使用 hard errors。(例如!,在 Map 中给出错误而不是 Nothing。)也许比运行时错误更好,但也许你现在可以摆脱错误。

有一些粘合在一起要做,然后一些文件输入/输出要做。对于文件输入/输出,readshow您的Accounts.

您不必这样做 - 这只是一种方法。(好吧,两个,如果你把列表和地图算作两种方法。)玩得开心!

于 2012-10-28T17:11:20.290 回答
3

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

于 2012-10-28T14:09:26.760 回答