2013-08-25 43 views
3

我是Haskell的新手,我遇到了问题。我需要编写一个函数,将列表分割成一个列表,列表中出现'分隔'。如何通过删除特定分隔将列表拆分为列表(Haskell)

+0

你第一次刺激算法是什么?你可以先尝试显式递归或者先解决一个简单的问题(其中分隔符是单个Char)。 – jev

+0

如果可以用空格替换分隔符,则可以用':'替换分隔符。到目前为止,你有什么? – bheklilr

回答

7

我会尽力帮助您开发的如何开发通过递归上列出的工作职能的认识。了解如何首先以“低级”方式进行操作是很有帮助的,这样您就可以更好地理解在实际代码中更常见的“高级”方式中发生的事情。

首先,你必须想想你要使用的数据类型的性质。该列表是在某种意义上递归定义的类型的在Haskell的典型的例子:一个列表要么是空列表[]或它与经由a : list列表合并一些列表元素a。这是唯一的两种可能性。我们将空列表称为基本情况,因为它是在其定义中未引用自身的情况。如果没有基本的情况,递归永远不会“谷底”,并会无限期地继续下去!

,有两种情况,一个list的定义,这意味着你必须在与列表工作的函数的定义考虑两种情况。在Haskell中考虑多个案例的规范方法是模式匹配。 Haskell语法提供了许多方法可以做到模式匹配,但我只使用基本的case表达现在:

case xs of 
    [] -> ... 
    x:xs' -> ... 

就是这两种情况下,一个必须考虑的列表。第一个匹配文字空列表构造函数;第二个元素与元素添加构造函数:相匹配,并且还将两个变量xxs'绑定到列表中的第一个元素以及包含其余元素的子列表。

如果你的函数传递一个是第一种情况相匹配列表中,那么你知道,无论是最初的名单是空的,或者您已完成列表中一路过去的最后一个元素的递归。无论哪种方式,都没有更多的列表要处理;你要么完成了(如果你的调用是尾递归的),或者你需要将你的答案构造的基本元素传回给调用这个元素的函数(通过返回它)。如果你的答案是一个列表,那么基本元素通常是空列表[]

如果你的函数传递一个第二情况下匹配列表,那么你知道它是通过一个非空列表,而且你有一对夫妇必然有用值的新变量。根据这些变量,你需要决定两件事情:

  1. 我怎么做我的一个元素算法的一步,假设我有从列表其余执行了正确的答案?
  2. 如何将该步骤的结果与在列表的其余部分执行结果相结合?

一旦你想出了这些问题的答案,你需要构造一个表达式来组合它们;为列表的其余部分获取答案只是在列表的其余部分调用递归调用,然后您需要执行第一个元素和组合的步骤。

这里有一个简单的例子,发现一个列表

listLength :: [a] -> Int 
listLength as = 
    case as of 
    [] -> 0     -- The empty list has a length of 0 
    a:as' -> 1 + listlength as' -- If not empty, the length is one more than the 
           -- length of the rest of the list 

这里的长度是另外一个例子,从列表中删除匹配的元素现在

listFilter :: Int -> [Int] -> Int 
listFilter x ns = 
    case ns of 
    [] -> []       -- base element to build the answer on 
    n:ns' -> if n == x 
       then listFilter x ns'  -- don't include n in the result list 
       else n : (listFilter x ns') -- include n in the result list 

,你问的问题是多一点点很困难,因为它涉及次要的“列表匹配”递归以识别列表中基本递归的分隔符。向递归函数添加额外参数有时会很有帮助,以便保存关于问题所在位置的额外信息。它也可能模式匹配在同一时间两个参数通过把它们放在一个元组:

case (xs, ys) of 
    ([] , [] ) -> ... 
    (x:xs', [] ) -> ... 
    ([] , y:ys') -> ... 
    (x:xs', y:ys') -> ... 

希望这些提示将帮助您对您的问题取得了一些进展!

+0

很好的解释,很容易理解像我这样的新手 – keduadoi

3

让我们看看问题是否可以明显减少。

假设splitList是用xs调用split和ys作为分隔符的。如果xs为空,问题是最小的,那么问题的答案是什么?在这里得到正确的答案很重要,因为归纳解决方案取决于这个决定。但我们可以稍后做出这个决定。

好的,所以对于可缩减的问题,列表xs不是空的。所以,它至少有一个head元素h和较小的问题t,列表的尾部:你可以匹配xs @(h:t)。如何获得较小问题的解决方案?那么,splitList可以通过函数的定义来解决这个问题。所以现在的技巧是找出如何为更大问题(h:t)构建解决方案,当我们知道解决较小问题zs = splitList t ys的解决方案时。这里我们知道zs是列表[[a]]的列表,并且因为t可能是最小的问题,所以zs很可能是最小问题的解决方案。所以,无论你用zs做什么,即使是解决最小的问题,它也必须是有效的。

splitList [] ys = ... -- some constant is the solution to the smallest problem 
    splitList [email protected](h:t) ys = let zs = splitList t ys 
          in ... -- build a solution to (h:t) from solution to t 
+0

tks,所以这是首先想到如何编写递归函数的方法 – keduadoi

1

我不知道如何对它进行测试。任何人告诉我如何写一个.hs文件的函数,并使用winGHCi来运行此功能?

WinGHCi自动关联.hs文件,所以只需双击该文件并启动ghci。使用你最喜欢的编辑器对文件进行一些更改后,你可以使用ghci中的:r命令来重新加载文件。

要在修改拼写错误,键入错误并确保正确缩进后测试程序,请尝试调用您使用不同输入定义的函数(或使用QuickCheck)。备注Maybe定义为Just xNothing。您可以使用fromMaybe来提取x(并为Nothing情况提供默认值)。

也尝试确保模式匹配是详尽的。