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

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)

dav*_*420 7

在结果的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,bd.

我们可以继续这样:

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代码的建设性建议.