2011-05-01 76 views
3

如何從Haskell中的字符串列表中獲得搜索匹配?如何從Haskell中的字符串列表中獲得搜索匹配?

module Main 
    where 
import List 
import IO 
import Monad 

getLines = liftM lines . readFile 

main = do 
    putStrLn "Please enter your name: " 
    name <- getLine 
    list <- getLines "list.txt" 
    -- mapM_ putStrLn list -- this part is to list out the input of lists 
+1

list.txt的內容是如何格式化的?我猜你想過濾包含單詞名稱的行嗎? – 2011-05-01 13:56:13

回答

3

如果您wan't在你LIST.TXT包含名稱的所有行的列表, 你可以簡單地使用

filter (isInfixOf name) list 

,但我不知道如果我理解你的問題正確。

12

要做的第一件重要的首要原則是儘可能多地從mainIO中獲得更多的想法。 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] -> BoolfrankJ :: String -> String -> String。我們希望將其納入我們的定義frankJ

因此,以「提供輸入」爲matchClean,我們需要一個函數來把我們從一個長字符串用換行來刺的名單(姓名),其matchClean需求:這就是前奏功能lines

但是我們還需要決定如何處理BoolmatchClean可以產生價值;如我們所知,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合理的候選材料,我們餵養到我們的定義IOmain

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,但我認爲這不會有太大影響。