0 haskell types tuples knapsack-problem
我正在尝试用输入解决分数背包问题,
[("label 1", value, weight), ("label 2", value, weight), ...]
Run Code Online (Sandbox Code Playgroud)
和输出,
[("label 1", value, solution_weight), ("label 2", value, solution_weight), ...]
Run Code Online (Sandbox Code Playgroud)
但我一直收到错误computeKnapsack:
"Couldn't match expected type `(t1, t2, t0)' with actual type `[a0]`"
Run Code Online (Sandbox Code Playgroud)
我无法理解问题可能是什么.我正在尝试创建一个三项目元组列表.我怎样才能让它停止期待一个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))))
Run Code Online (Sandbox Code Playgroud)
在结果的then分支中computeKnapsack是单个3元组,但在else分支中它是3元组的列表.
我要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))))
Run Code Online (Sandbox Code Playgroud)
首先,我将说明如果第一个参数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))))
Run Code Online (Sandbox Code Playgroud)
它使我们能够摆脱if测试,使代码整体更短,更容易理解.
接下来,我将解构x:
computeKnapsack [] _ = []
computeKnapsack ((a,b,_,d):xs) weightLeft =
(a, b, ((floor (weightLeft / d))*d)) : (computeKnapsack xs (weightLeft-(floor (weightLeft / d)*d)))
Run Code Online (Sandbox Code Playgroud)
您可能更愿意遵循leftaroundabout的建议来创建具有有意义名称的记录类型.但是,如果你继续使用一个元组,通过模式匹配解构它是不是用你更清楚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
Run Code Online (Sandbox Code Playgroud)
在这里,我发现在两个不同的地方计算了相同的值,并将该值提取到自己的命名变量中.weight只需要计算一次而不是两次,所以computeKnapsack现在效率稍高.更重要的是,我现在明白computeKnapsack在做什么.
我知道你是Haskell的新手.请将此作为有关如何编写更清晰的Haskell代码的建设性建议.