如何重写Haskell中的单词函数

时间:2013-12-28 15:42:44

标签: haskell

如何在Haskell中重写单词函数,即不使用格式的情况,而是使用其他格式?到目前为止,我已经尝试过:

import Data.Char 
mywords s
       | dropWhile isSpace s == "" = []
       | dropWhile isSpace s == s' = w : mywords s'' 
            where (w, s'') = break isSpace s'

import Data.Char 
mywords s = if dropWhile isSpace s == "" then [] else w : mywords s'
            where (w, s') = break isSpace s

但他们不起作用。他们为什么不工作?如何以更容易理解的不同方式重写单词功能?

原始前奏代码:

import Data.Char
mywords s                 =  case dropWhile isSpace s of
                                "" -> []
                                s' -> w : mywords s''
                                      where (w, s'') =
                                             break isSpace s'

2 个答案:

答案 0 :(得分:4)

第一个问题是行

| dropWhile isSpace s == s'

此时你还没有真正定义过s'。相反,我认为你想要更接近的东西

myWords :: String -> [String]
myWords s | s' == ""  = ""
          | otherwise = word : myWords rest
  where s' = dropWhile isSpace s
        (word, rest) = break isSpace s'

现在我们定义s'并检查它是否为空字符串,否则我们会先粘贴第一个单词并继续运行。

对于第二个,你忘记了删除前导空格。因此当你传递它" foo"时,它会将其分解为单词("", " foo")并永远循环。相反,你只想要与第一个解决方案相同的想法

myWords' s = if s' == "" then [] else word : myWords' rest
  where s' = dropWhile isSpace s
        (word, rest) = break isSpace s'

请注意,这些基本上是相同的,因为我们只是使用像花哨的表达式一样的守卫。

如果你想要更短的代码,我想你可以做类似

的事情
myWords' s = if dropWhile isSpace s == "" then [] else uncurry (:).fmap myWords'.break isSpace.dropWhile isSpace $ s

这有点无意义且难以辨认。 3行代码非常简短。

答案 1 :(得分:0)

在内部循环中,我们构建了一个配有Bool标签的单词列表。如果标记是True,则最顶层的单词是“正在构建”,我们可以在其前面添加字符。如果标记为False,则最顶层的单词为“done”,因此任何新的非空白字符都必须被视为新最顶层单词的最后一个字符。

import Data.Char

words = fst . loop
  where
    loop "" = ([], False)
    loop (c:cs)
      | isSpace c = (words cs, False)
      | otherwise =
        case loop cs of
          (ws, False) -> ([c]:ws, True)    -- c is the last character of a new word
          (w:ws, True) -> ((c:w):ws, True) -- c can be prepended to the current word