我有两个函数:
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]
上面的函数总是成功地返回我所期望的double类型。重要的分界线是(fromIntegral(tvn) / fromIntegral(points))
。函数calctvn(此处未显示)和变量点总是整数,因此fromminintegral()是必需的。
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仍然返回正确除数的双精度数,而updatetvd总是插入值3.0。如果从updatetvd内部调用calctvd,就好像Haskell不计算分母。
更新1:然而,这种奇怪的现象似乎依赖于上述两个函数的一些复杂性。我试着把它分解成一个简单的例子:
testcalctvd :: Double
testcalctvd = fromIntegral(3) / fromIntegral(4) :: Double
testupdatetvd :: Double
testupdatetvd = testcalctvd
但是,testcalctvd和teststupdatetvd都返回正确的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
我的猜测是,当您手动调用calctvd
时,您传递的p
参数也不是ps
参数的第一个元素。但是当updatetvd
调用calctvd
时,p = head ps
.
我不能确定,因为您既没有向我们展示失败的测试用例,也没有向我们展示perkAndPreqs
的定义(如果points
被错误地计算为1
,那么关于原因的线索可能在perkAndPreqs
中)。