2011-05-01 73 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,但我认为这不会有太大影响。