我正在尝试用输入来解决分数背包问题,
[("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))))
答案 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
等函数更清晰。
同样,代码现在更短,更容易理解,但如果我们使用的名称比snd4
,a
和b
更有意义,则可能会有所帮助。
我们可以继续这样:
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
。