Haskell Assignment - 将String拆分为单词所需的方向

时间:2012-03-28 12:45:37

标签: haskell

几个星期前,我们开始撰写关于Haskell的论文,刚收到我们的第一份作业。我知道SO不喜欢家庭作业问题,所以我不打算问怎么做。相反,如果有人能用这个推动我朝着正确的方向发展,我将非常感激。看来它可能不是一个特定的问题,它在讨论/社区维基中会更合适吗?

问题:对字符串进行标记,即:“Hello,World!” - > [“你好”,“世界”]

来自Java背景,我不得不忘记关于通常的方法。问题是我对Haskell仍然很无能为力。这就是我想出来的:

module Main where

main :: IO()
main = do putStrLn "Type in a string:\n"
          x <- getLine
          putStrLn "The string entered was:"
          putStrLn x
          putStrLn "\n"
          print (tokenize x)

tokenize :: String -> [String]
tokenize [] = []
tokenize l = token l ++ tokenize l

token :: String -> String
token [] = []
token l = takeWhile (isAlphaNum) l

第一个明显错误是什么? 谢谢。

5 个答案:

答案 0 :(得分:8)

第一个明显的错误是

tokenize l = token l ++ tokenize l

(++) :: [a] -> [a] -> [a]附加两个相同类型的列表。自token :: String -> String(和type String = [Char])以来,从该行推断的tokenize类型为tokenize :: String -> String。 你应该在这里使用(:) :: a -> [a] -> [a]

该行中的下一个错误是在递归调用中,您再次传递相同的输入l,因此您有一个无限递归,总是在不做任何更改的情况下执行相同操作。您必须从递归调用的参数的输入中删除第一个标记(以及更多)。

另一个问题是你的token假设输入以字母数字字符开头。

您还需要一个函数来确保传递给token的内容的条件。

答案 1 :(得分:4)

这一行导致一个无限列表(这是好的,因为Haskell是懒惰的,所以列表只是“按需”构建),因为它重复出现而且参数没有变化:

tokenize l = token l ++ tokenize l

当tokenize被称为:

时,我们可以看到发生了什么
tokenize l = token l ++ tokenize l
           = token l ++ (token l ++ tokenize l)
           = token l ++ (token l ++ (token l ++ tokenize l))
           = ...

要阻止这种情况发生,您需要将参数更改为tokenize,以便明智地重复:

tokenize l = token l ++ tokenize <something goes here>

答案 2 :(得分:2)

正如其他人已经指出你的错误,只是一点提示:虽然你已经发现了非常有用的takeWhile功能,但你应该看一下span,因为这在这里可能会更有帮助

答案 3 :(得分:1)

这里面有一些与解析器monad类似的东西。但是,由于您是Haskell的新手,因此您不太可能理解解析monad的工作原理(或在代码中使用它们)。为了给你提供基础知识,请考虑你想要的:

tokenize :: String -> [String]

这需要一个字符串,将其整理成更多部分,并生成与输入字符串中的单词对应的字符串列表。我们怎么能代表这个呢?我们想要做的是找到一个处理单个字符串的函数,并在空白的第一个符号处将该字符串添加到单词序列中。但然后你必须处理剩下的东西。 (即,字符串的其余部分。)例如,假设您想要标记化:

  

棕色狐狸跳了

首先拉出“The”,然后继续处理“棕色狐狸跳跃”(注意第二个字符串开头的空格)。你将以递归方式执行此操作,因此您需要一个递归函数。

突出的自然解决方案是采取一些你积累的东西到目前为止你已经被标记化的一组字符串,继续咀嚼当前输入,直到你击中空白,然后积累你的东西已经在当前的字符串中看到了(这导致了一个实现,你主要是在处理东西,然后偶尔反转东西)。

答案 4 :(得分:-1)

你的练习对我来说似乎有点挑战,所以我决定只为自我训练解决它。这就是我想出的:

import Data.List
import Data.Maybe

splitByAnyOf yss xs = 
  foldr (\ys acc -> concat $ map (splitBy ys) acc) [xs] yss

splitBy ys xs = 
  case (precedingElements ys xs, succeedingElements ys xs) of
    (Just "", Just s) -> splitBy ys s
    (Just p, Just "") -> [p]
    (Just p, Just s) -> p : splitBy ys s
    otherwise -> [xs]

succeedingElements ys xs = 
  fromMaybe Nothing . find isJust $ map (stripPrefix ys) $ tails xs

precedingElements ys xs = 
  fromMaybe Nothing . find isJust $ map (stripSuffix ys) $ inits xs
  where
    stripSuffix ys xs = 
      if ys `isSuffixOf` xs then Just $ take (length xs - length ys) xs
      else Nothing

main = do
  print $ splitBy "!" "Hello, World!"
  print $ splitBy ", " "Hello, World!"
  print $ splitByAnyOf [", ", "!"] "Hello, World!"

输出:

["Hello, World"]
["Hello","World!"]
["Hello","World"]