Converting quarters, dimes, and pennies to dollars and cents in Haskell - haskell

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.")
|

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

Related

Converting different types into string

The goal is to build a program to report the transactions for a particular stock in a human-readable format. For example, for our test data set, the transactions on the stock VTI will be printed
as:
Bought 100 units of VTI for 1104 pounds each on day 1
Bought 50 units of VTI for 1223 pounds each on day 5
Sold 150 units of VTI for 1240 pounds each on day 9
Here is the test transaction code:
type Transaction = (Char, Int, Int, String, Int)
test_log :: [Transaction]
test_log = [('B', 100, 1104, "VTI", 1),
('B', 200, 36, "ONEQ", 3),
('B', 50, 1223, "VTI", 5),
('S', 150, 1240, "VTI", 9),
('B', 100, 229, "IWRD", 10),
('S', 200, 32, "ONEQ", 11),
('S', 100, 210, "IWRD", 12)
]
For this, I thought is would be best to split each section into slices where they can be concatenated at the end.
--Converting transaction to string
transaction_to_string :: Transaction -> String
transaction_to_string (action: units: stocks: price: day) =
let display = action ++ "Bought"
slice1 = units ++ "of"
slice2 = stocks ++ "for"
slice3 = price ++ "on day"
slice4 = day
in
slice1 ++ slice2 ++ slice3 + slice4
The error I am receiving is this. It is giving a type error but I am unsure why due to the type function used at the top:
• Couldn't match type ‘[Char]’ with ‘Char’
Expected: [Char]
Actual: [[Char]]
• In the second argument of ‘(++)’, namely ‘slice4’
In the second argument of ‘(++)’, namely ‘slice3 ++ slice4’
In the second argument of ‘(++)’, namely
‘slice2 ++ slice3 ++ slice4’
|
| slice1 ++ slice2 ++ slice3 ++ slice4
A first attempt:
transaction_to_string :: Transaction -> String
transaction_to_string (action, units, stocks, price, day) =
-- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ tuple, not list
let display = show action ++ "Bought" -- << convert non-strings using `show`
slice1 = show units ++ "of" -- <<
slice2 = show stocks ++ "for" -- <<
slice3 = price ++ "on day"
slice4 = show day -- <<
in
display ++ slice1 ++ slice2 ++ slice3 ++ slice4
You could improve this by:
adding spaces in the right places
formatting the string better: the order of the concatenation seems a bit off (test it!)
properly handling display, perhaps using something like:
let display | action == 'B' = "Bought"
| action == 'S' = "Sold"
| otherwise = "Uhh.. what?"
Assuming Transaction were not a type synonym, ideally you would make it an instance of Show. For instance, if we used a record type.
data Transaction = Transaction {
action :: Char,
units :: Int,
stocks :: String,
price :: Int,
day :: Int
}
instance Show Transaction where
show (Transaction {action=a, units=u, stocks=s, price=p, day=d}) = str
where
a' = case a of
'B' -> "Bought"
'S' -> "Sold"
_ -> "Unknown action"
str = a' ++ " " ++ show u ++ " units of " ++ s ++
" at $" ++ show p ++ " on day " ++ show d
Now:
Prelude> Transaction {action='B', units=100, stocks="FOO", price=56, day=7}
Bought 100 units of FOO at $56 on day 7

How to make a Haskell function calculate ticket prices?

I am new to Haskell and am trying to write a function that does the following:
asks user to enter "Youth" "Adult" or "Senior" and indicate of the one they pick
function then calculates total price of tickets (Y = $10.50, A = $20, S = $15)
Sample output:
Enter type of ticket and count:
Senior 7
Total price is: 95.00
Here is what I have come up with so far:
calcPrice :: (String a) => a -> b -> b
calcPrice x y =
if x == "Youth"
then "Total price :" ++ 10.5 * y
else if x == "Adult"
then "Total price :" ++ 20 * y
else if x == "Senior"
then "Total price :" ++ 15 * y
else "Invalid input."
...but I get this error:
homework8.hs:31:15: error:
• Expected kind ‘* -> Constraint’, but ‘String’ has kind ‘*’
• In the type signature: calcPrice :: (String a) => a -> b -> b
|
31 | calcPrice :: (String a) => a -> b -> b |
Any help is appreciated, but my main questions are:
How do we specify the types if we want to output a string and a number?
In other variants, an error message appeared that it was not happy about the comparison in the if/else if statements. why?
How do I make the function output something if it can only be called with arguments that the user has no idea to input until the message is displayed?
EDIT_________________
Here is the new code after making the changes you all have mentioned:
calcPrice :: (Integral a) => String -> a -> String
calcPrice x y =
if x == "Youth"
then "Total price :" ++ Show(10.5 * y)
else if x == "Adult"
then "Total price :" ++ Show(20 * y)
else if x == "Senior"
then "Total price :" ++ Show(15 * y)
else "Invalid input."
and I now get this error...
homework8.hs:34:31: error:
• Data constructor not in scope: Show :: a -> [Char]
• Perhaps you meant variable ‘show’ (imported from Prelude)
|
34 | then "Total price :" ++ Show(10.5 * y) | ^^^^
homework8.hs:36:31: error:
• Data constructor not in scope: Show :: a -> [Char]
• Perhaps you meant variable ‘show’ (imported from Prelude)
|
36 | then "Total price :" ++ Show(20 * y) | ^^^^
homework8.hs:38:31: error:
• Data constructor not in scope: Show :: a -> [Char]
• Perhaps you meant variable ‘show’ (imported from Prelude)
|
38 | then "Total price :" ++ Show(15 * y) | ^^^^
Failed, no modules loaded.
How do we specify the types if we want to output a string and a number?
One way is to give back a tuple of a string and a number:
calcPrice :: String -> Double -> (String, Double)
calcPrice x y =
if x == "Youth"
then ("Total price :", 10.5 * y)
else if x == "Adult"
then ("Total price :", 20 * y)
else if x == "Senior"
then ("Total price :", 15 * y)
else ("Invalid input.", 0/0)
However, as the comments pointed out, in this case it's probably more sensible to encode and append the number part into the string. Conversion from many types to String is easily done with the show function (which is a method of the Show (uppercase) typeclass – note how the show function you use in your value level code is lowercase)
calcPrice :: String -> Double -> String
calcPrice x y =
if x == "Youth"
then "Total price :" ++ show (10.5 * y)
else if x == "Adult"
then "Total price :" ++ show (20 * y)
else if x == "Senior"
then "Total price :" ++ show (15 * y)
else "Invalid input."
The other sub-questions are unclear to me – maybe remove them here and flesh them out as separate questions.
Some stylistic remarks:
Rather than doing a bunch of separate if x== statements, it's neater and in general also more efficient to use case (which is very flexible in Haskell, and often works even for types that can't be equality-compared):
calcPrice x y = case x of
"Youth" -> "Total price :" ++ show (10.5 * y)
"Adult" -> "Total price :" ++ show (20 * y)
"Senior" -> "Total price :" ++ show (15 * y)
_ -> "Invalid input."
Alternative syntax for the same thing: you can simply write a bunch of separate function clauses for specific values of x, rather than only one that accepts any x
calcPrice "Youth" y = "Total price :" ++ show (10.5 * y)
calcPrice "Adult" y = "Total price :" ++ show (20 * y)
calcPrice "Senior" y = "Total price :" ++ show (15 * y)
calcPrice _ _ = "Invalid input."
Not just in Haskell, but any language it's good to follow the DRY principle. A standard way of this is to define local variables, like
calcPrice x y = case x of
"Youth" -> totalPrice ++ show (10.5 * y)
"Adult" -> totalPrice ++ show (20 * y)
"Senior" -> totalPrice ++ show (15 * y)
_ -> "Invalid input."
where totalPrice = "Total price :"
don't do it this way, because the actual code-duplication (++ show, * y) is still there! Instead, define local functions (which are also variables)
calcPrice x y = case x of
"Youth" -> priceMul 10.5
"Adult" -> priceMul 20
"Senior" -> priceMul 15
_ -> "Invalid input."
where priceMul μ = "Total price :" ++ show (μ*y)
In a bigger project you should probably separate the “is the input valid?” from the actual calculation logic, else you'll soon have weird errors popping up deep in your code where you never expected them. Worse, if the error is merely “signalled” by a dedicated string value "Invalid input", it becomes very difficult to find where the error did happen.
Advocates of dynamic languages argue that this is what unit tests are there for, but a static type system reduces the need for that a lot. Specifically, you can accept instead of a string which could easily have lots of invalid values, a type that only has those values that are actually valid:
data PricingTier = Youth | Adult | Senior
calcPrice :: PricingTier -> Double -> String
calcPrice x y = case x of
Youth -> priceMul 10.5
Adult -> priceMul 20
Senior -> priceMul 15
where priceMul μ = "Total price :" ++ show (μ*y)

Removing digits from an integer

Here's a homework problem I came across:
Input an integer, greater than or equal to 0. Multiply it by 5, add 6 to the product, multiply by 4, add 9 and multiply by 5. Then, remove the last two digits of the final number and subtract 1. Output the answer.
Here's my code:
1 main = do
2 putStrLn "enter a non-negative integer: "
3 input <- getLine
4 let i = (read input :: Int)
5 print ((((i * 5) + 6) * 4 + 9) * 5)/100-1
Here, I'm trying to truncate the last two digits by dividing it by 100, since this works in other languages.
However, it gives me this error and I'm not sure what it means:
$ runhaskell Computations.hs
Computations.hs:5:5: error:
• No instance for (Fractional (IO ())) arising from a use of ‘/’
• In the first argument of ‘(-)’, namely
‘print ((((x * 5) + 6) * 4 + 9) * 5) / 100’
In a stmt of a 'do' block:
print ((((x * 5) + 6) * 4 + 9) * 5) / 100 - 1
In the expression:
do { putStrLn "enter a non-negative integer: ";
input1 <- getLine;
let x = (read input1 :: Int);
print ((((x * 5) + 6) * 4 + 9) * 5) / 100 - 1 }
Computations.hs:5:5: error:
• No instance for (Num (IO ())) arising from a use of ‘-’
• In a stmt of a 'do' block:
print ((((x * 5) + 6) * 4 + 9) * 5) / 100 - 1
In the expression:
do { putStrLn "enter a non-negative integer: ";
input1 <- getLine;
let x = (read input1 :: Int);
print ((((x * 5) + 6) * 4 + 9) * 5) / 100 - 1 }
In an equation for ‘main’:
main
= do { putStrLn "enter a non-negative integer: ";
input1 <- getLine;
let x = ...;
.... }
So, can anyone explain what the error means?
Are there any other solutions better than trucating by a divisor?
How can I remove digits at arbitrary positions? For example, remove the first, second and sixth digits from an integer?
ps: input and output should match if done correctly.
Update: I've changed "/" to "div" and it gives me this:
Computations.hs:5:12: error:
• Couldn't match expected type ‘(Integer -> Integer -> Integer)
-> Integer -> Integer’
with actual type ‘Int’
• The function ‘(((i * 5) + 6) * 4 + 9) * 5’
is applied to two arguments,
but its type ‘Int’ has none
In the first argument of ‘(-)’, namely
‘((((i * 5) + 6) * 4 + 9) * 5) div 100’
In the first argument of ‘print’, namely
‘(((((i * 5) + 6) * 4 + 9) * 5) div 100 - 1)’
This part is strange: "The function ‘(((i * 5) + 6) * 4 + 9) * 5’ is applied to two arguments", why does haskell interpret it as a function?
Can anyone explain what the error means?
The precedence in your first line is off - infix functions (like /) usually have a higher precedence than normal ones, so print (...) / 100 is equivalent to (print ...) / 100, which is obviously problematic. You can wrap everything in brackets, or use the $ function:
print $ ((((i * 5) + 6) * 4 + 9) * 5) / 100 - 1
Now as you've constrained i to be an Int, this will still give an error: / is only defined for instances of the Fractional typeclass, and Int isn't. You want integer division, div or quot, which operates only on Integrals (of which Int is an instance) and perform truncation as you want:
print $ ((((i * 5) + 6) * 4 + 9) * 5) `div` 100 - 1
Note the backticks (`), which allow a normal function to be used infix. You could write this as:
print $ (div ((((i * 5) + 6) * 4 + 9) * 5) 100) - 1
But then the brackets are making things really hard to read.
Are there any other solutions better than truncating by a divisor?
In general probably not, but as mentioned on your other question, this particular equation will always give you the same result as your input, so you can just write:
main = getLine >>= print
How can I remove digits at arbitrary positions?
Converting to a string and removing characters is likely your best bet. Something like the following will work, although it's arguably a bit dense:
removeDigits :: [Int] -> Int -> Int
removeDigits indices x = read . reverse . filterIndices indices . reverse . show $ x
filterIndices :: [Int] -> [a] -> [a]
filterIndices inds elems = map snd . filter ((`notElem` inds) . fst) . zip [1..] $ elems
Note this treats the last digit as the "1st" digit - it's a bit more natural to refer to digits with.
An (in my opinion) easier to read representation of your existing code is:
transform = (subtract 1) . (`quot` 100) . (*5) . (+9) . (*4) . (+6) . (*5)
With this way of writing it, composition overrides the arithmetic precedence laws, letting us write it how it's read ("times 5, add 6, times 4, ..."). We have to use subtract 1, as -1 is interpreted as the literal value -1, not as a unary function.
Removing digits at arbitrary positions is an interesting problem. This is probably easiest to do by converting to string and performing string manipulation, then reading back as an Int. Since Int implements both Show and Read, you can do:
type Digit = Int
removeDigits :: [Digit] -> Int -> Int
removeDigits digits = read . go 1 . show
where
go _ [] = []
go i (c:cs) | i `elem` digits = go cs (i+1)
| otherwise = c : go cs (i+1)
-- N.B. I chose 1-indexing here instead of 0-indexing because of your word choice
-- "remove the first, second, and sixth digits" maps naturally to [1, 2, 6],
-- though programmers may find that off-putting. YMMV.
removeDigits here could be re-written as
read [c | (i, c) <- zip [1..] (show n), i `notElem` digits]

Strange compile error in Haskell

Why does the type of max prod nextProd get inferred as Int->Int->Int instead of just Int in the below function?
import qualified Data.Vector as DV
largestProduct::DV.Vector Int->(Int, Int)
largestProduct digits = foldl lastProdAndMax (0,0) [1..((DV.length digits) - 13)] where
lastProdAndMax _ 1 = (first, first) where first = DV.foldl (*) 1 $ DV.take 13 digits
lastProdAndMax (prod, max) i = (nextProd, max prod nextProd)
where nextProd = (prod `div` ((DV.!) digits (i-13))) * ((DV.!) digits i)
Your error is in
lastProdAndMax (prod, max) i = (nextProd, max prod nextProd)
^^^
in that scope, max is a Int (overloading the max function).

Why isn't show treated as a conversion in haskell?

I'm still very much trying to get into haskell, but I've noticed something that annoyed me quite a bit.
In the book "Learn You a Haskell for Great Good!" there's this part that shows the use of guards in pattern matching, in the case of the book it was a small function that calculates the bmi of a person, it went a little something like this (parts changed slightly to not infringe copyright or whatever):
bmiCalc :: (RealFloat a) => a -> a -> String
bmiCalc weight height
| bmi <= 18.5 = "skinny"
| bmi <= 25.0 = "normal"
| bmi <= 30.0 = "fat"
| otherwise = "obese"
where bmi = weight / height ^ 2
That's all fine and dandy the code works as advertised, but I thought, what if it also showed what the bmi it calculated was along with the text?
So I re-wrote the code to this:
bmiCalc :: (RealFloat a) => a -> a -> String
bmiCalc weight height
| bmi <= 18.5 = "skinny, " ++ show bmi
| bmi <= 25.0 = "normal, " ++ show bmi
| bmi <= 30.0 = "fat, " ++ show bmi
| otherwise = "obese, " ++ show bmi
where bmi = weight / height ^ 2
Expecting "show" to work like .toString does in java and c#
Boy was I wrong.
ghci gave me this big nasty error message:
Could not deduce (Show a) arising from a use of `show'
from the context (RealFloat a)
bound by the type signature for
bmiCalc :: RealFloat a => a -> a -> String
at file.hs:1:16-48
Possible fix:
add (Show a) to the context of
the type signature for bmiCalc :: RealFloat a => a -> a -> String
In the second argument of `(++)', namely `show bmi'
In the expression: "skinny, " ++ show bmi
In an equation for `bmiCalc':
bmiCalc weight height
| bmi <= 18.5 = "skinny, " ++ show bmi
| bmi <= 25.0 = "normal, " ++ show bmi
| bmi <= 30.0 = "fat, " ++ show bmi
| otherwise = "obese, " ++ show bmi
where
bmi = weight / height ^ 2
Failed, modules loaded: none.
why is that? why doesn't it allow me to append what appears to return a string, to a string? I mean as far as I've understood "skinny, " ++ show bmi is a string... which is exactly what the type signature says I have to return
so what did I do wrong here?
Change the type signature to:
bmiCalc :: (RealFloat a, Show a) => a -> a -> String
Because you want to use the member function show, from the Show typeclass; but you haven't specified that in the function constraint, and ghci has no way to infer that to be correct.
RealFloat isn't a showable type. You'll have to add a show constraint.

Resources