无法匹配期望的类型`(t1,t2,t0)'实际类型为`[a0]`

时间:2012-08-05 16:56:52

标签: haskell types tuples knapsack-problem

我正在尝试用输入来解决分数背包问题,

[("label 1", value, weight), ("label 2", value, weight), ...]

和输出,

[("label 1", value, solution_weight), ("label 2", value, solution_weight), ...]

但我一直在computeKnapsack中收到错误:

"Couldn't match expected type `(t1, t2, t0)' with actual type `[a0]`"

我无法理解问题所在。我正在尝试创建一个三项目元组列表。我怎样才能让它停止期待一个3个入口的元组?

fst3 (a,b,c) = a
snd3 (a,b,c) = b
trd3 (a,b,c) = c
fst4 (a,b,c,d) = a
snd4 (a,b,c,d) = b
trd4 (a,b,c,d) = c
qud4 (a,b,c,d) = d

sortFrac (a1, b1, c1, d1) (a2, b2, c2, d2)
  | d1 > d2 = GT
  | d1 <= d2 = LT

fracKnap (x:xs) =
    fractionalKnapsack (x:xs) []

fractionalKnapsack (x:xs) fracList =
    if length (x:xs) <= 1
        then computeKnapsack (sortBy sortFrac (((fst3 x),(snd3 x),(trd3 x),(snd3 x) / (trd3 x)):fracList)) 100
        else fractionalKnapsack xs (((fst3 x),(snd3 x),(trd3 x),(snd3 x) / (trd3 x)):fracList)

computeKnapsack (x:xs) weightLeft =
    if length (x:xs) <= 1
        then (fst4 x, snd4 x, ((floor (weightLeft / (qud4 x)))*(qud4 x)))
        else (fst4 x, snd4 x, ((floor (weightLeft / (qud4 x)))*(qud4 x))):(computeKnapsack xs (weightLeft-(floor (weightLeft / (qud4 x))*(qud4 x))))

3 个答案:

答案 0 :(得分:7)

then的{​​{1}}分支中,结果是一个3元组,但在computeKnapsack分支中,它是一个3元组的列表。


我要为你重写else。我将从您的版本开始修复错误:

computeKnapsack

首先,我要说明如果computeKnapsack (x:xs) weightLeft = if length (x:xs) <= 1 then [(fst4 x, snd4 x, ((floor (weightLeft / (qud4 x)))*(qud4 x)))] else (fst4 x, snd4 x, ((floor (weightLeft / (qud4 x)))*(qud4 x))) : (computeKnapsack xs (weightLeft-(floor (weightLeft / (qud4 x))*(qud4 x)))) 的第一个参数是空列表会发生什么:

computeKnapsack

它使我们能够摆脱computeKnapsack [] _ = [] computeKnapsack (x:xs) weightLeft = (fst4 x, snd4 x, ((floor (weightLeft / (qud4 x)))*(qud4 x))) : (computeKnapsack xs (weightLeft-(floor (weightLeft / (qud4 x))*(qud4 x)))) - 测试,使代码整体更短,更容易理解。

接下来,我将解构if

x

您可能更愿意遵循leftaroundabout的建议来创建具有有意义名称的记录类型。但是如果你继续使用元组,通过模式匹配对其进行解构比使用computeKnapsack [] _ = [] computeKnapsack ((a,b,_,d):xs) weightLeft = (a, b, ((floor (weightLeft / d))*d)) : (computeKnapsack xs (weightLeft-(floor (weightLeft / d)*d))) fst4等函数更清晰。

同样,代码现在更短,更容易理解,但如果我们使用的名称比snd4ab更有意义,则可能会有所帮助。

我们可以继续这样:

d

在这里,我发现在两个不同的地方计算了相同的值,并将该值提取到自己的命名变量中。 computeKnapsack [] _ = [] computeKnapsack ((a,b,_,d):xs) weightLeft = (a, b, weight) : (computeKnapsack xs (weightLeft - weight)) where weight = floor (weightLeft / d) * d 只需要计算一次而不是两次,因此weight现在更有效率。更重要的是,我现在明白computeKnapsack正在做什么。

我知道你是Haskell的新手。请将此作为有关如何编写更清晰的Haskell代码的建设性建议。

答案 1 :(得分:2)

我冒昧地清理了computeKnapsack功能,以便您更清楚地看到问题:

computeKnapsack (x:xs) weightLeft =
 let e = (fst4 x, snd4 x, floor (weightLeft / qud4 x) * qud4 x)
  in if length (x:xs) <= 1
     then e
     else e:computeKnapsack xs (weightLeft - floor (weightLeft / qud4 x) * qud4 x)

我的变化纯粹是装饰性的。即使在我的更改后,您的computeKnapsack函数仍然被破坏,算法错误,编码风格也不好。

您可以从重写版本中看到您的if语句有两个分支,一个返回一个元组,另一个返回一个元组列表。您可以通过更改第一个分支来返回包含单个元素的列表来修复它:

computeKnapsack (x:xs) weightLeft =
 let e = (fst4 x, snd4 x, floor (weightLeft / qud4 x) * qud4 x)
  in if length (x:xs) <= 1
     then [e]
     else e:computeKnapsack xs (weightLeft - floor (weightLeft / qud4 x) * qud4 x)

此外,在向StackOverflow提交第三个问题之前,请花点时间完成Haskell的入门教程,如http://learnyouahaskell.com/,这将有助于解决您的许多问题。

答案 2 :(得分:0)

fractionalKnapsack的当时引发错误的一个问题。 在该行中,您使用元组作为输入而不是computeKnapsack来调用函数list