要做的第一件重要的首要原則是儘可能多地從main
或IO
中獲得更多的想法。 main
應儘可能包含所有IO
,也許除了IO
之外都包含您在模塊中其他位置定義的純術語。您的getLines
正在不必要地混合它們。
因此,要獲取的方式進行,我們應該有一個main
這就是說,
main =
do putStrLn "What is your name?"
name <- getContents
names <- readFile "names.txt"
putStrLn (frankJ name names)
- 又或許IO
從我們從得到一切的更嚴峻的隔離:
main =
do putStrLn greeting
name <- getContents
names <- readFile nameFile
putStrLn (frankJ name names)
與 '純粹的' 術語一起:
greeting, nameFile :: String
greeting = "What is your name?"
nameFile = "names.txt"
不管怎樣,我們現在真的在Haskell陸:現在的問題是要弄清楚什麼純功能:
frankJ :: String -> String -> String
應該的。
我們可以用一個簡單的匹配功能啓動:當第一個字符串出現字符串列表上,我們獲得了比賽:
match :: String -> [String] -> Bool
match name namelist = name `elem` namelist
-- pretty clever, that!
,或者我們可能要歸位,讓空白的名字的開始和結尾都是我們給出的,名單上的名字不會影響匹配。這裏有一個很蹩腳的方式來做到這一點:
clean :: String -> String
clean = reverse . omitSpaces . reverse . omitSpaces
where omitSpaces = dropWhile (== ' ')
然後,我們可以提高我們的老match
,即elem
:
matchClean :: String -> [String] -> Bool
matchClean name namelist = match (clean name) (map clean namelist)
現在,我們需要按照類型,找出如何適應型例如,matchClean:: String -> [String] -> Bool
與frankJ :: String -> String -> String
。我們希望將其納入我們的定義frankJ
。
因此,以「提供輸入」爲matchClean
,我們需要一個函數來把我們從一個長字符串用換行來刺的名單(姓名),其matchClean
需求:這就是前奏功能lines
。
但是我們還需要決定如何處理Bool
,matchClean
可以產生價值;如我們所知,frankJ
返回String
。讓我們繼續與問題的笨笨分解:
response :: Bool -> String
response False = "We're sorry, your name does not appear on the list, please leave."
response True = "Hey, you're on the A-list, welcome!"
現在,我們有我們可以撰寫成函數frankJ :: String -> String -> String
合理的候選材料,我們餵養到我們的定義IO
機main
:
frankJ name nametext = response (matchClean name (lines nametext))
-- or maybe the fancier:
-- frankJ name = response . matchClean name . lines
-- given a name, this
-- - pipes the nametext through the lines function, splitting it,
-- - decides whether the given name matches, and then
-- - calculates the 'response' string
所以在這裏,幾乎所有東西都是純函數的問題,並且很容易看出如何修正事物以進一步細化。例如,可能輸入的名稱和文本文件的行應進一步標準化。在比較之前,內部空間應限制在一個空間內。或者,也許有在名單上線一個逗號,因爲人們被列爲「姓,名」,等等,等等或許我們要響應函數使用人的名字:
personalResponse :: String -> Bool -> String
personalResponse name False = name ++ " is a loser, as far as I can tell, get out!"
personalResponse name True = "Ah, our old friend " ++ name ++ "! Welcome!"
與
一起
frankJpersonal name = personalResponse name . matchClean name . lines
當然有一百萬種方法可以解決這個問題。例如,有regex
庫。來自Hackage的優秀且簡單的Data.List.Split
也可能有用,但我不確定它可以被Hugs使用,您可能正在使用它。
我注意到你使用的是輸入模塊的老式名稱。我所寫的只使用Prelude,因此不需要導入,但其他模塊現在按照分層命名系統稱爲「System.IO」,「Data.List」和「Control.Monad」。我想知道你是否正在使用舊的教程或手冊。也許愉快的「學習你一個Haskell」網站會更好?他肯定他使用ghc
,但我認爲這不會有太大影響。
list.txt的內容是如何格式化的?我猜你想過濾包含單詞名稱的行嗎? – 2011-05-01 13:56:13