Reputation: 2402
I have two functions:
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]
The above function always succeeds in returning the double that I would expect. The important line is the division (fromIntegral(tvn) / fromIntegral(points))
. The function calctvn (not shown here) and the variable points are always integers, so fromIntegral() is necessary.
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
Essentially, this second function should just insert the value of the first function into a list. However, it only inserts the numerator of the term (fromIntegral(tvn) / fromIntegral(points))
. I proved this by changing that line in calctvd to 3 / fromIntegral(points)
. With this, calctvd still returned the correctly divided double, whereas updatetvd always inserted a value of 3.0. It is as if Haskell does not evaluate the denominator if calctvd is called from inside updatetvd.
Update 1:
However, it appears that this oddity relies on some complexity in the above two functions. I tried to break it down into a simple example:
testcalctvd :: Double
testcalctvd = fromIntegral(3) / fromIntegral(4) :: Double
testupdatetvd :: Double
testupdatetvd = testcalctvd
However, both testcalctvd and testupdatetvd return the correct 0.75.
Update 2:
Here is an example straight from Terminal, using the test term 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}
Update 3:
Here is the perkAndPreqs function, which is probably the culprit, but I am not sure how much sense it will make:
--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
Upvotes: 0
Views: 165
Reputation: 47062
My guess is that when you call calctvd
by hand, the p
parameter you pass is not also the first element of the ps
parameter. But when calctvd
is called from updatetvd
, p = head ps
.
I cannot be sure, because you've shown us neither failing test cases nor the definition of perkAndPreqs
(if points
is being miscalculated as 1
, the clue as to why is likely to be in perkAndPreqs
).
Upvotes: 1