在Haskell库中有一个名为“words”的函数,它接受一个字符串并返回一个列表,其中的元素是字符串中的单词。基本上它删除空格并存储单词。例如:
words "Hello there mister person guy" == ["Hello", "there", "mister", "person", "guy"]
现在我们被要求自己实施。到目前为止,我已经尝试了两天,我真的无法想出一个解决方案。我试过在线查找,但实际上找不到任何东西。所以我请你帮忙。
请记住,虽然我是Haskell的初学者,因此不熟悉高级概念,所以如果可能的话,请在解释中详细说明:)。
答案 0 :(得分:4)
嗯,解决这个问题的方法(或者说真正的大多数问题)就是把它分解成更小的问题,你可以将它们的解决方案结合起来解决你的问题,然后分别解决这些问题。有a standard function from Data.List
that you can use to solve this problem:
应用于谓词span :: (a -> Bool) -> [a] -> ([a], [a])
span
和列表p
的
xs
返回一个元组,其中第一个元素是满足xs
元素的最长前缀(可能为空)p
和第二个元素是列表的其余部分。
所以一个可能的策略是:
span
将列表分成两部分:不包含空格的最大初始前缀,其余部分如果您不允许在课堂上使用库函数,那么我要做的就是编写我自己的库函数版本。
答案 1 :(得分:2)
听起来像是家庭作业,所以我不想只写答案,但是......
一些提示 -
首先编写您的类型签名。在编写函数之前,请在签名上使用Hoogle查看是否存在有用的东西。
你会想要使用递归(即 - 一旦你找到一个单词,你可以将它从字符串的其余部分拆分,然后在余数上重新应用你的单词函数。)
记住字符串只是Haskell中的列表,因此请查看Data.List函数并查看可能有用的内容。
答案 2 :(得分:2)
基本上它会移除空格并存储单词
我知道您对该陈述的意图,但应该更准确地说明为
它将字符串拆分为空格并返回单词列表
这给我们提供了一个非常具体的案例。这个问题归结为找到空间。简单的方法是使用takeWhile
:
myWords :: String -> [String]
myWords "" = []
myWords text = takeWhile (/= ' ') text : ???
我不会给你完整的解决方案,但这应该可以帮助你开始。你需要弄清楚???
的位置。此外,这与words
函数不完全相同,因为它还处理重复的空格:
> words "This is a test"
["This","is","a","test"]
所以你必须弄清楚如何做到这一点。
答案 3 :(得分:0)
这是基本的想法,不应该太难以把它放在代码上:
答案 4 :(得分:0)
一开始,你可以在案例/情境中思考,当你遍历一个清单时:
import Data.Char (isSpace)
noWord (x:xs)
| isSpace x = noWord xs
-- is still space, do nothing and check next.
| not (isSpace x) = isWord [x] xs
-- is a new word - apply isWord.
noWord [] = []
-- if the fun ends with space.
isWord akku (x:xs)
| not (isSpace x) = isWord (akku ++ [x]) xs
-- is still a word, so add x to the word and continue.
| isSpace x = akku : noWord xs
-- is no more a word, save the word and do some noWord's.
isWord akku [] = akku : []
-- when list is empty, give the cached word back and end the list.
myWords = noWord
-- start with no word.
main = print $ myWords " hell oh world! "
-- try it
给你:
["hell","oh","world!"]
答案 5 :(得分:-1)
你可以像命令式语言一样使用Haskell,使用if构造和变量赋值。您可以使用递归代替循环。这导致了以下(幼稚)解决方案:
(警告:Haskell大师,请你把目光移开)
wordsRecursive input =
wordsRecursive2 [] [] input
where
wordsRecursive2 words currentWord input =
if (length input == 0)
then
currentWord : words
else
let (i:is) = input in
if (i == ' ')
then
wordsRecursive2 (currentWord : words) [] is
else
wordsRecursive2 words (i:currentWord) is
这段代码很难看。它有许多明显的问题,但主要问题是它使用递归。有一种说法是“递归是函数式编程的GOTO”。所以在可能的情况下,我们应该用一些更高级别的函数替换递归。
在这种情况下,我们可以简单地使用折叠。
wordsFold input = (\ (word, words) -> word:words) $ foldl wordsFold2 ([], []) input
where
wordsFold2 (currentWord, words) ' ' = ([], currentWord : words)
wordsFold2 (currentWord, words) i = (i : currentWord, words)
此函数使用折叠而不是递归。折叠将“wordsFold2”应用于输入字符串中的每个字符,以及一些中间结果。中间结果是返回每个先前应用的wordsFold2。在这种情况下,它由(部分)当前单词和已找到(完整)单词的列表组成。初始中间结果由空的当前单词和已找到的单词的空列表组成。
在每个步骤中,函数wordsFold2执行以下几个
它使用哪个选项取决于当前字符的值。
折叠操作的结果是最后的中间结果。部分(\ (word, words) -> word:words)
然后将最后一个单词添加到单词列表中。
哦,顺便说一句,因为你应该做自己的功课,我已经为你做了一个练习。我的解决方案将结果“倒退”。你必须稍微调整一下才能得到正确的结果:-P