2012-08-05 2 views
0

Я пытаюсь решить дробную задачу о рюкзаке с входом,не мог бы соответствовать ожидаемому типу `(t1, t2, t0)» с фактическим типом `[a0]`

[("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-х кортежей. Как я могу заставить его перестать ожидать одного кортежа с 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)))) 
+5

Просьба _do_ переписать его без этих уродливых 'fst'' snd' 'trd'' qud' функций, это действительно затрудняет понимание того, что происходит. Для каждой записи кортежа должен быть какой-то смысл, описывать его как тип записи ('data KnapsackItem = KnapsackItem {propA :: Foo, propB :: Bar, propC :: Quu}') – leftaroundabout

+0

Очень сложно сказать что 4-кортеж должен представлять, что делает его действительно трудным следовать вашему коду. –

ответ

7

В ветке thencomputeKnapsack результатом является одиночный 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)))) 

Во-первых, я хочу сказать, что произойдет, если первый аргумент 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:

computeKnapsack []    _   = [] 
computeKnapsack ((a,b,_,d):xs) weightLeft = 
    (a, b, ((floor (weightLeft/d))*d)) : (computeKnapsack xs (weightLeft-(floor (weightLeft/d)*d))) 

Вы могли бы предпочесть последовать совет 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 

Здесь я заметил, что же значение рассчитывается в двух разных местах, и экстрагируют это значение в его собственном имени переменной. weight нужно рассчитать только один раз, а не дважды, поэтому computeKnapsack теперь немного более эффективен. Что еще более важно, я теперь понимаю, что делает computeKnapsack.

Я понимаю, что вы новичок в Haskell. Пожалуйста, примите это как конструктивные предложения о том, как вы можете писать более четкий код Haskell.

0

Одна из проблем, которая вызывает эту ошибку в то время fractionalKnapsack. В этой строке вы вызываете функцию computeKnapsack с кортежем как вход вместо list.

+0

Спасибо. Как я могу сделать sortBy sortFrac (((fst3 x), (snd3 x), (trd3 x), (snd3 x)/(trd3 x)): fracList) список? Я думал, что, добавив его в fracList, который является [], он сделает его списком>< – user1577039

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/ которые помогут решить многие проблемы.