Haskell只返回除法的分子(有时)



我有两个函数:

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中)。

最新更新