I'm trying to convert quarters, dimes, and pennies to dollars and cents, but I can't seem to get the code to run.
I tried this code:
-- Declaration
toCents :: Int -> Int -> Int -> Int
toDollar :: Int -> Int -> Int -> Int
-- Definition
toCents quarter dime penny = quarter*25 dime*10 penny
toDollar quarter dime penny = (toCents quarter dime penny) / 100) - ((toCents quarter dime penny mod 100) / 100)
main :: IO()
main = do
let quarter = 12
let dime = 67
let penny = 43
let sumDollar = toDollar quarter dime penny
let sumCents = toCents quarter dime penny - (toDollar quarter dime penny) * 100
print ("Conversion of " show quarter " quarters, " show dime " dimes, and " show penny " pennies to dollars and cents:")
print(sumDollar " dollars and " sumCents " cents.")
And it resulted to this error:
[1 of 1] Compiling Main ( main.hs, main.o )
main.hs:7:68: error:
• Couldn't match expected type ‘(Integer -> Integer -> Integer)
-> Integer -> Int’
with actual type ‘Int’
• The function ‘toCents’ is applied to five arguments,
but its type ‘Int -> Int -> Int -> Int’ has only three
In the first argument of ‘(/)’, namely
‘(toCents quarter dime penny mod 100)’
In the second argument of ‘(-)’, namely
‘((toCents quarter dime penny mod 100) / 100)’
|
7 | toDollar quarter dime penny = (toCents quarter dime penny / 100) - ((toCents quarter dime penny mod 100) / 100)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
main.hs:17:8: error:
• Couldn't match expected type ‘[Char]’ with actual type ‘Int’
• In the first argument of ‘( )’, namely ‘sumDollar’
In the first argument of ‘print’, namely
‘(sumDollar " dollars and " sumCents " cents.")’
In a stmt of a 'do' block:
print (sumDollar " dollars and " sumCents " cents.")
|
17 | print(sumDollar " dollars and " sumCents " cents.")
| ^^^^^^^^^
main.hs:17:40: error:
• Couldn't match expected type ‘[Char]’ with actual type ‘Int’
• In the first argument of ‘( )’, namely ‘sumCents’
In the second argument of ‘( )’, namely ‘sumCents " cents."’
In the second argument of ‘( )’, namely
‘" dollars and " sumCents " cents."’
|
17 | print(sumDollar " dollars and " sumCents " cents.")
|
CodePudding user response:
The expression toCents quarter dime penny mod 100
is parsed as
((((toCents quarter) dime) penny) mod) 100
or
( ( ( (toCents quarter
) dime
) penny
) mod
) 100
That looks completely weird, though it's not that weird if you keep in mind how currying works: it corresponds to, in an uncurried language,
toCents(quarter, dime, penny, mod, 100)
Which is of course still nonsense though: you're feeding mod
as an argument to the function toCents
, instead of using it right there as an operator. Infix operators with letter names must be written in backticks to apply them, like 37`mod`4
, which is the same as mod 37 4
. Infix operators always bind weaker than prefix function application, so if you had written
toCents quarter dime penny `mod` 100
then this would have parsed as
mod (toCents quarter dime penny) 100
which is probably what you intended. That does however not mean it's good for the task. What you're doing with
foo/100 - (foo`mod`100)/100
is a very roundabout attempt of implementing simple round-to-negative integer division.
It kind of works in Python, but even there it doesn't really do what it should: Python automatically converts the integers foo
and 100
to floats to perform the division, then subtracts to floats from each other and the result is still a float though it happens to have zero fractional part.
Haskell doesn't even allow this mess to happen: it will complain that the /
operator is not available on integers. You you really wanted that, you would have to explicitly convert to floats.
You don't want that though: you should simply use the built-in integer division operator instead
toDollar quarter dime penny = toCents quarter dime penny `div` 100
...Assuming it should really have round-to-negative behaviour.
Even better would be to structure your code and data properly, which would avoid both redundant computations and cryptic Int -> Int -> ...
signatures:
data DollarValue = DollarValue {
dollarPartVal, centPartVal :: Int
}
data DollarCoins = DollarCoins {
quarterCoinCount, dimeCoinCount, pennyCoinCount :: Int
}
coinsValue :: DollarCoins -> DollarValue
coinsValue (DollarCoins q d p) = DollarValue dollars cents
where (dollars, cents) = (25*q 10*d p)`divMod`100
import Text.Printf
main = do
let quarter = 12
dime = 67
penny = 43
let DollarValue sumDollars sumCents
= coinsValue $ DollarCoins quarter dime penny
printf
"Conversion of %i quarters, %i dimes, and %i pennies: %i dollars and %i cents.\n"
quarter dime penny sumDollars sumCents