我是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"
答案 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
上使用show
和Accounts
。
你不必这样做 - 这只是一种方法。 (好吧,两个,如果你将列表与地图统计为两种方法。)玩得开心!
答案 1 :(得分:3)
事实上,所有问题都归结为你的第三个问题。您正在寻找的是一种数据结构,允许您将用户名映射到用户帐户。我建议查看Data.Map
容器类型,看看如何使用它。