简体   繁体   English

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

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

I'm trying to solve this excercise but I can't think of a solution. 我正在尝试解决这一问题,但我想不出解决方案。 I need to check if a list is palindrome, taking these considerations: 考虑以下因素,我需要检查列表是否为回文式:
If the list is simple I just need to check if it's palindrome horizontally, but if it's a nested list I need to check both, vertical and horizontal. 如果列表很简单,我只需要检查水平回文,如果它是嵌套列表,则需要同时检查垂直和水平。
I also need to keep in mind that each element inside the list has to be palindrome by itself, for example: 我还需要记住,列表中的每个元素本身都必须是回文,例如:

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

for this case I just created a single function that uses reverse : 对于这种情况,我只创建了一个使用反向的函数:

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

also this case, for example: 同样是这种情况,例如:

B = [[1,2,1],[1,2,1]] horizontally palindrome and to check if it's palindrome vertically I just transpose it, [[1,1],[2,2],[1,1]] and the result is, yes, it is palindrome both ways. B = [[1,2,1],[1,2,1]]水平回文,并检查它是否垂直回文,我只是将其转置, [[1,1],[2,2],[1,1 ]] ,结果是,都是回文。

I solved this by using the function transpose to evaluate vertically if it is palindrome and then, using the function unidimensional that I used before I check if it's palindrome horizontally, everything fine: 我通过使用转置函数垂直评估回文率,然后使用在检查水平回文率之前使用的一维函数解决了所有问题:

--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)



the problem is here: 问题在这里:

The input my program needs to receive has to be something like this: 我的程序需要接收的输入必须是这样的:

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

My problem is: my function palindrome should receive as a parameter a list [a] , but palindrome should work for nested lists, like [[[a]]] or [[a]] 我的问题是:我的函数回文应接收列表[a]作为参数,但是回文应对嵌套列表起作用,例如[[[a]]][[a]]

palindrome is the function that takes the input. 回文是接受输入的功能。

The thing is that when I get a simple list, my head, which is x is a number, and xs which is the tail, would be the rest of the numbers, and that's ok, but when palindrome receives a nested list, for example [[[2,2],[2,2]],[[1,1],[1,1]]] the head, x is now [[2,2],[2,2]] , so I can't use my function like, bidimensional because [[2,2],[2,2]] is not a list anymore, when I try to call bidimensional with xs which is [[2,2],[2,2]] I get an error: xs is now type a and not [[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]]

My question is : How can I make my function palindrome, work with any type of list (simple and nested) taking into account the error I mentioned before. 我的问题是 :考虑到我之前提到的错误,我该如何使我的函数回文功能与任何类型的列表一起使用(简单和嵌套)。 Thanks in advance! 提前致谢!

My question is: How can I make my function palindrome, work with any type of list (simple and nested) taking into account the error I mentioned before. 我的问题是:考虑到我之前提到的错误,我如何使我的函数回文符能够与任何类型的列表一起使用(简单和嵌套)。 Thanks in advance! 提前致谢!

Let's think about this hypothetical palindrome function and try to figure out what type signature it would need. 让我们考虑一下这种假设的palindrome功能,并尝试找出它需要哪种类型的签名。 (Thinking about a function in terms of its type signature always helps me.) (从函数的类型签名方面考虑函数总是有帮助的。)

Suppose palindrome has a signature palindrome :: [x] -> Bool 假设palindrome具有签名palindrome :: [x] -> Bool

We what the following statements to be true: 我们下面的陈述是正确的:

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

In the first two assertions, palindrome specializes to [Integer] -> Bool , so x is Integer in those cases. 在前两个断言中, palindrome专精于[Integer] -> Bool ,因此在这些情况下xInteger The only sensible implementation with x === Integer is simply to check if the supplied list of integers is a palindrome, ie, check that the first element equals the last, pop those off and repeat (or, equivalently, check that xs equals reverse xs as you have). x === Integer的唯一明智的实现只是检查所提供的整数列表是否是回文,即检查第一个元素是否等于最后一个元素,弹出并重复(或等效地,检查xs等于reverse xs )。 We can use this algorithm whenever x is an instance of Eq . 每当xEq的实例时,我们都可以使用此算法。

In the last two properties, palindrome specializes to [[Integer]] -> Bool , so x is [Integer] there. 在最后两个属性中, palindrome[[Integer]] -> Bool ,因此x在此处是[Integer] It seems like we should be able to detect that x is itself a list of integers, and then know that we need to recursively apply palindrome to each inner list. 看来我们应该能够检测到x本身是一个整数列表,然后知道我们需要对每个内部列表递归应用回文。 However, Haskell polymorphism doesn't work that way. 但是,Haskell多态不能那样工作。 In order for a function to be polymorphic over a type parameter x , we need to define a single implementation of that function that works the same way no matter what type x happens to be . 为了使函数在类型参数x上具有多态性,我们需要定义该函数的单个实现, 无论x是什么类型 ,其实现方式都相同。

In other words, to define a polymorphic function palindrome :: [x] -> Bool , our implementation cannot know anything about the type parameter x . 换句话说,要定义多态函数palindrome :: [x] -> Bool ,我们的实现不能知道有关类型参数x任何信息。 This forces us to use the same implementation when x === [Integer] as we used when x === Integer , which would evaluate to True instead of False for the final test case. 这迫使我们使用相同的实现时, x === [Integer]因为我们使用时, x === Integer ,这将评估为True而不是False的最后测试案例。

You won't be able to make your palindrome function work the way you want it to for nested lists in Haskell if you insist on the input being standard [] types. 如果坚持输入为标准[]类型,则将无法使palindrome函数按您希望的方式在Haskell中的嵌套列表中使用。

One thing you might do is have your palindrome function take an extra parameter of type Int that tells the function how deeply to check. 您可能要做的一件事是让palindrome功能接受一个额外的Int类型的参数,该参数告诉该功能进行检查的深度。 In that case, you'd need to know ahead of time how deeply nested your input is. 在这种情况下,您需要提前知道输入的嵌套深度。 Another thing you might do is write your palindrome function to take input in some other data structure besides [] , like a Tree , or something with arbitrary nesting. 您可能要做的另一件事是编写palindrome函数以在[]之外的其他数据结构中接受输入,例如Tree或具有任意嵌套的内容。 Maybe you can write your function to accept a Value , a type that represents arbitrary JSON values from the popular library Aeson . 也许您可以编写函数来接受Value ,该类型表示流行的库Aeson中的任意JSON值。

Note: It's probably a good idea for palindrome [] to be True , no? 注意:palindrome []设为True可能是个好主意,不是吗?

You could use a typeclass. 您可以使用类型类。

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

For a two-dimensional list, you are checking if the list is a palindrome, "both horizontally and vertically". 对于二维列表,您正在检查列表是否是“水平和垂直”回文。 This can be done without the transpose function: the list is a palindrome "vertically" if the list is a palindrome, and the list is a palindrome "horizontally" if every sublist is a palindrome. 这可以在没有transpose功能的情况下完成:如果列表是回文,则列表是“垂直”回文,如果每个子列表都是回文,则列表是“水平”回文。 The second instance checks both. 第二个instance检查两者。

For a one-dimensional list, the second instance simply checks if the list is a palindrome. 对于一维列表,第二个instance仅检查列表是否为回文。 In this case, the && all palindrome xs might as well not be there: since the first instance specifies that Integer s are always palindromes, all palindrome xs always evaluates to True . 在这种情况下, && all palindrome xs也可能不存在:由于第一个instance指定Integer始终是回文,因此all palindrome xs总是求值为True This can be seen as the "base case" for this recursive algorithm. 这可以看作是此递归算法的“基本情况”。

This will work for any depth of nested lists. 这将适用于任何深度的嵌套列表。 You can also instantiate the class for other base data types, or (I'm pretty sure) even for ALL types of class Eq (although this leads to overlapping instances which is its own can of worms). 您还可以实例化其他基本数据类型的类,或者甚至可以对所有类型的Eq类实例化(尽管我很确定)(尽管这会导致实例重叠,这是蠕虫自身的行为)。

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

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