繁体   English   中英

Haskell多态函数,用于检查列表是否为回文

[英]Haskell polymorphic function that checks if a list is palindrome

我正在尝试解决这一问题,但我想不出解决方案。 考虑以下因素,我需要检查列表是否为回文式:
如果列表很简单,我只需要检查水平回文,如果它是嵌套列表,则需要同时检查垂直和水平。
我还需要记住,列表中的每个元素本身都必须是回文,例如:

A = [1,2,3,3,2,1]是回文

对于这种情况,我只创建了一个使用反向的函数:

unidimensional:: (Eq a) => [a] -> Bool
unidimensional [] = error"List is empty."
unidimensional xs = xs == reverse xs

同样是这种情况,例如:

B = [[1,2,1],[1,2,1]]水平回文,并检查它是否垂直回文,我只是将其转置, [[1,1],[2,2],[1,1 ]] ,结果是,都是回文。

我通过使用转置函数垂直评估回文率,然后使用在检查水平回文率之前使用的一维函数解决了所有问题:

--Checks if it's palindrome horizontally and vertically 
bidimensional:: (Eq a) => [[a]] -> Bool
bidimensional [[]] = error"Empty List."
bidimensional (xs) = if left_right xs && up_down xs then True else False
--Checks if it's palindrome horizontally:
left_right (x:xs) = if x == reverse x then
if xs /= [] then bidimensional xs else True 
else False
--Checks if it's palindrome vertically:
up_down:: (Eq a) => [[a]] -> Bool
up_down (xs) = left_right ys where ys = transpose xs
transpose:: [[a]]->[[a]]
transpose ([]:_) = []
transpose x = (map head x) : transpose (map tail x)



问题在这里:

我的程序需要接收的输入必须是这样的:

> palindrome [[1,2,2,1], [3,7,9,9],[3,7,9,9], [1,2,2,1]]

我的问题是:我的函数回文应接收列表[a]作为参数,但是回文应对嵌套列表起作用,例如[[[a]]][[a]]

回文是接受输入的功能。

问题是,当我得到一个简单列表时,我的头(即x是一个数字,而xs是尾部)将是其余的数字,这没关系,但是当回文式收到一个嵌套列表时,例如[[[[2,2],[2,2]],[[1,1],[1,1]]]的头部, x现在是[[2,2],[2,2]] ,所以我不能用我的功能一样,二维因为[2,2],[2,2]是不是一个列表了,当我尝试调用二维与XS[2,2],[2, 2]]我收到一个错误: xs现在输入a而不是[[a]]

我的问题是 :考虑到我之前提到的错误,我该如何使我的函数回文功能与任何类型的列表一起使用(简单和嵌套)。 提前致谢!

我的问题是:考虑到我之前提到的错误,我如何使我的函数回文符能够与任何类型的列表一起使用(简单和嵌套)。 提前致谢!

让我们考虑一下这种假设的palindrome功能,并尝试找出它需要哪种类型的签名。 (从函数的类型签名方面考虑函数总是有帮助的。)

假设palindrome具有签名palindrome :: [x] -> Bool

我们下面的陈述是正确的:

palindrome [1, 2, 1] === True
palindrome [1, 2, 2] === False
palindrome [[1, 2, 1], [3, 4, 3], [1, 2, 1]] === True
palindrome [[1, 2, 2], [3, 4, 3], [1, 2, 2]] === False

在前两个断言中, palindrome专精于[Integer] -> Bool ,因此在这些情况下xInteger x === Integer的唯一明智的实现只是检查所提供的整数列表是否是回文,即检查第一个元素是否等于最后一个元素,弹出并重复(或等效地,检查xs等于reverse xs )。 每当xEq的实例时,我们都可以使用此算法。

在最后两个属性中, palindrome[[Integer]] -> Bool ,因此x在此处是[Integer] 看来我们应该能够检测到x本身是一个整数列表,然后知道我们需要对每个内部列表递归应用回文。 但是,Haskell多态不能那样工作。 为了使函数在类型参数x上具有多态性,我们需要定义该函数的单个实现, 无论x是什么类型 ,其实现方式都相同。

换句话说,要定义多态函数palindrome :: [x] -> Bool ,我们的实现不能知道有关类型参数x任何信息。 这迫使我们使用相同的实现时, x === [Integer]因为我们使用时, x === Integer ,这将评估为True而不是False的最后测试案例。

如果坚持输入为标准[]类型,则将无法使palindrome函数按您希望的方式在Haskell中的嵌套列表中使用。

您可能要做的一件事是让palindrome功能接受一个额外的Int类型的参数,该参数告诉该功能进行检查的深度。 在这种情况下,您需要提前知道输入的嵌套深度。 您可能要做的另一件事是编写palindrome函数以在[]之外的其他数据结构中接受输入,例如Tree或具有任意嵌套的内容。 也许您可以编写函数来接受Value ,该类型表示流行的库Aeson中的任意JSON值。

注意:palindrome []设为True可能是个好主意,不是吗?

您可以使用类型类。

class Palindrome a where
  palindrome :: a -> Bool

instance Palindrome Integer where
  palindrome _ = True

instance (Eq a, Palindrome a) => Palindrome [a] where
  palindrome xs = xs == reverse xs && all palindrome xs

对于二维列表,您正在检查列表是否是“水平和垂直”回文。 这可以在没有transpose功能的情况下完成:如果列表是回文,则列表是“垂直”回文,如果每个子列表都是回文,则列表是“水平”回文。 第二个instance检查两者。

对于一维列表,第二个instance仅检查列表是否为回文。 在这种情况下, && all palindrome xs也可能不存在:由于第一个instance指定Integer始终是回文,因此all palindrome xs总是求值为True 这可以看作是此递归算法的“基本情况”。

这将适用于任何深度的嵌套列表。 您还可以实例化其他基本数据类型的类,或者甚至可以对所有类型的Eq类实例化(尽管我很确定)(尽管这会导致实例重叠,这是蠕虫自身的行为)。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM