根据你的例子,
ghci> mergePoints [(1, 3), (1, 4), (5, 5)] [(1, 1), (4, 4)]
(0, 0)
[ (0.0, 0.0), (1.0, 1.0),
(1.0, 3.0), (1.0, 4.0), (4.0, 4.0),
(5.0, 5.0)]
这两个列表中的每一个都以自己的速度消耗,因此zip 不适合这里,因为它以相同的速度消耗其参数列表。
对此进行编码的最简单方法是使用带有模式匹配的直接递归定义,该定义将比较两个头部元素并根据比较结果使用一个或另一个。
也许您还需要将它们与提供的第三点进行比较,以防它不是最小的。
那么,关于您的代码。
从示例输入输出来看,点应该是按顺序出来的。我们可以在元组定义字典顺序时比较它们。你已经在这样做了。通过一个小的语法修复,您的代码是:
mergePoints1 l1 l2 o = o ++ [f | (a, b) <- zip l1 l2,
let f if a < b then f = [a, b]
else f = [b, a]]
这不是一个有效的 Haskell。 Haskell 中没有赋值,只有定义:
mergePoints2 l1 l2 o = o ++ [f | (a, b) <- zip l1 l2,
let f = if a < b then [a, b] else [b, a]]
但是这个列表推导会创建一个元组列表列表,因为我们将它们创建为f = [a,b] 或f = [b,a]。逐一使用这些点,我们需要从这些短列表中逐一“绘制”它们,使用
mergePoints3 l1 l2 o = o ++ [r | (a, b) <- zip l1 l2,
r <- if a < b then [a, b] else [b, a]]
(使用r 表示“结果”,而不是f)。最后一个错误是++ 连接了两个列表,但o 不是一个。那么它一定是
mergePoints4 l1 l2 o = [o] ++ merge1 l1 l2
merge1 l1 l2 = [r | (a, b) <- zip l1 l2,
r <- if a < b then [a, b] else [b, a]]
现在它可以工作了,但没有做它应该做的事情。事实上,由于它的输出仍然不能保证是有序的,我们甚至可以把它写成
merge2 l1 l2 = l1 ++ l2
where -- the definition of the built-in `++`:
[] ++ l2 = l2
l1 ++ [] = l1
(x:t1) ++ l2 = x : (t1 ++ l2)
或者我们可以使用
从
both 列表中提取元素
merge3 l1 l2 = l1 ++ l2
where
[] ++ l2 = l2
l1 ++ [] = l1
(x:t1) ++ (y:t2) = x : y : (t1 ++ t2) -- or:
-- = x : ((y:t2) ++ t1)
当然,按位置逐个取出元素可能会扰乱它们的顺序。您尝试使用merge1 纠正此问题可以重写为
merge1b l1 l2 = l1 ++ l2
where
[] ++ l2 = l2
l1 ++ [] = l1
(x:t1) ++ (y:t2) = if x < y then x : y : (t1 ++ t2)
else y : x : (t1 ++ t2)
但它仍然可以打乱订单。我们假设我们的两个输入是有序的,增加列表,其中每个元素都小于列表中跟随它的元素。所以我们只需要使用这些知识,小心只提取其中一个元素:
merge4 l1 l2 = l1 ++ l2
where
[] ++ l2 = l2
l1 ++ [] = l1
(x:t1) ++ (y:t2) = if x < y then x : (_ ++ (y:t2))
else _ : _
您需要通过将_s 替换为实际代码来完成此定义。
额外问题:在两个元素相等的情况下,Haskell 中merge 的通常定义更喜欢它的“左”参数而不是“右”参数。对代码进行单字符编辑,以实现此目的。