我正试图解决这个问题,但我想不出解决方案。
我需要检查列表是否是回文,考虑以下因素:
如果列表很简单,我只需要检查它是否是水平的回文,但如果它是嵌套列表,我需要同时检查垂直和水平。
我还需要记住列表中的每个元素都必须它本身就是回文,例如:
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]] ,结果是,是的,两种方式都是回文。
我通过使用transpose函数来解决这个问题,如果是palindrome则垂直评估,然后使用我在检查它是否是水平回文之前使用的一维函数,一切都很好:
--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 调用bidimensional时, [[2,2],[ 2,2]] 我收到错误: xs 现在输入 a 而不是 [[a]]
我的问题是:我如何制作我的函数回文,使用任何类型的列表(简单和嵌套),同时考虑到我之前提到的错误。提前谢谢!
答案 0 :(得分:0)
我的问题是:我如何制作我的函数回文,使用任何类型的列表(简单和嵌套)考虑到我之前提到的错误。提前谢谢!
让我们考虑这个假设的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
唯一明智的实现只是检查提供的整数列表是否是回文,即检查第一个元素是否等于最后一个,弹出那些并重复(或等效地检查{{1}你有平等xs
)。只要reverse xs
是x
的实例,我们就可以使用此算法。
在最后两个属性中,Eq
专门针对palindrome
,因此[[Integer]] -> Bool
为x
。看起来我们应该能够检测到[Integer]
本身就是一个整数列表,然后知道我们需要递归地将回文应用于每个内部列表。但是,Haskell多态性并不是那样的。为了使函数在类型参数x
上具有多态性,我们需要定义该函数的单个实现,其工作方式与相同,无论x
类型是什么
换句话说,要定义多态函数x
,我们的实现对类型参数palindrome :: [x] -> Bool
一无所知。这迫使我们在x
时使用x === [Integer]
时使用相同的实现,x === Integer
在最终测试用例时评估为True
而不是False
。
如果您坚持输入为标准palindrome
类型,那么您将无法使您的[]
函数按照您希望的方式在Haskell中嵌套列表工作。
您可能要做的一件事是让palindrome
函数采用类型Int
的额外参数来告诉函数检查的深度。在这种情况下,您需要提前知道输入的嵌套程度。您可能要做的另一件事是编写palindrome
函数以在[]
之外的其他数据结构中输入输入,例如Tree
或任意嵌套的内容。也许您可以编写函数来接受Value
,这是一种表示来自热门库Aeson的任意JSON值的类型。
注意: palindrome []
True
可能是个好主意,不是吗?
答案 1 :(得分:0)
你可以使用类型类。
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
也是如此(尽管这会导致重叠的实例,这是它自己的蠕虫)。