[英]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
,因此在这些情况下x
是Integer
。 x === Integer
的唯一明智的实现只是检查所提供的整数列表是否是回文,即检查第一个元素是否等于最后一个元素,弹出并重复(或等效地,检查xs
等于reverse xs
)。 每当x
是Eq
的实例时,我们都可以使用此算法。
在最后两个属性中, 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.