У меня есть две функции:
calctvd :: [Perk] -> [Perk] -> Perk -> Double
calctvd ps fs p = (fromIntegral(tvn) / fromIntegral(points)) :: Double
where
tvn = calctvn ps fs p
points = length $ [i | i <- perkAndPreqs ps p, i `notElem` fs]
Приведенная выше функция всегда успешно возвращает значение, которое я ожидаю.Важной чертой является деление (fromIntegral(tvn) / fromIntegral(points))
.Функция calctvn (здесь не показана) и переменные точки всегда являются целыми числами, поэтому необходима fromIntegral ().
updatetvd :: [Perk] -> [Perk] -> [Perk]
updatetvd [] _ = []
updatetvd ps fs
--If p is in the list of elements already taken, then do not update it
| p `elem` fs = [p] ++ updatetvd (tail ps) fs
--Otherwise, update the tvd value
| otherwise = [PerkImpl (tvd, school, skill, name, def, preqstr, pref)] ++ updatetvd (tail ps) fs
where
p = head ps
PerkImpl (_, school, skill, name, def, preqstr, pref) = p
tvd = calctvd ps fs p
По сути, эта вторая функция должна просто вставить значение первой функции в список.Тем не менее, он вставляет только числитель термина (fromIntegral(tvn) / fromIntegral(points))
.Я доказал это, изменив эту строку в calctvd на 3 / fromIntegral(points)
.При этом calctvd по-прежнему возвращал правильно разделенный double, тогда как updatetvd всегда вставлял значение 3.0.Как будто Хаскелл не вычисляет знаменатель, если calctvd вызывается изнутри updatetvd.
Обновление 1:
Однако, похоже, что эта странность связана с некоторой сложностью в вышеупомянутых двух функциях.Я попытался разбить его на простой пример:
testcalctvd :: Double
testcalctvd = fromIntegral(3) / fromIntegral(4) :: Double
testupdatetvd :: Double
testupdatetvd = testcalctvd
Однако и testcalctvd, и testupdatetvd возвращают правильные 0,75.
Обновление 2:
Вот примерпрямо из Терминала, используя тестовый термин 3 / fromIntegral(points)
:
> calctvd initial [] i17
0.6 {This is 3/5, because i17 has 5 points}
> updatetvd initial []
[...3.0...] {This is just the numerator 3}
Обновление 3:
Вот функция perkAndPreqs, которая, вероятно, является виновной, но я не уверен, какой смыслэто составит:
--Take a perk and return a list of that perk and all of its pre-requisites
perkAndPreqs :: [Perk] -> Perk -> [Perk]
perkAndPreqs _ NULL = []
perkAndPreqs ps p = [p] ++ perkAndPreqs ps preq
where
PerkImpl (_, _, _, _, _, preqstring, _) = p
preq = perkIdentifier preqstring ps