The Author Online Book Forums are Moving

The Author Online Book Forums will soon redirect to Manning's liveBook and liveVideo. All book forum content will migrate to liveBook's discussion forum and all video forum content will migrate to liveVideo. Log in to liveBook or liveVideo with your Manning credentials to join the discussion!

Thank you for your engagement in the AoF over the years! We look forward to offering you a more enhanced forum experience.

76375 (1) [Avatar] Offline
#1
sum_lazy.hs
[ 420 bytes ]
When I run the solution for Q22.1 I'll get the following output

~/Documents/projects/haskell ? ./simple_calc
21+34
33+55
simple_calc: simple_calc.hssmilie3,1)-(4,49): Non-exhaustive patterns in function calc

What's wrong here?
552234 (1) [Avatar] Offline
#2
I agree that this solution seems invalid.

The superficial problem is sampleInput is supposed to be ["21", "+", "123"], but is actually ["21 + 123"]. Without changing the signature of calc:

import Data.List.Split

calc :: [String] -> Int
calc (val1:"+":val2:rest) = read val1 + read val2
calc (val1:"*":val2:rest) = read val1 * read val2

main :: IO ()
main = do
  userInput <- getContents
  let expressions = (concatMap $ splitOn " ") . lines
  let values = expressions userInput
  print (calc values)


This lazily evaluates, but doesn't allow multiple expressions.

So, maybe the author meant:

import Data.List.Split

calc :: [String] -> Int
calc (val1:"+":val2:rest) = read val1 + read val2
calc (val1:"*":val2:rest) = read val1 * read val2

main :: IO ()
main = do
  userInput <- getContents
  let expressions = map (splitOn " ") . lines
  let values = expressions userInput
  print (map calc values)


This allows multiple expressions, but doesn't lazily evaluate (I think due to `print [a]`, but I don't understand why that happens).

Based on this theory, I tried:

import Data.List.Split

calc :: [String] -> Int
calc (val1:"+":val2:rest) = read val1 + read val2
calc (val1:"*":val2:rest) = read val1 * read val2

main :: IO ()
main = do
  userInput <- getContents
  let expressions = map (splitOn " ") . lines
  let values = expressions userInput
  mapM_ print (map calc values)


Which seems to completely satisfy the original problem definition:

$ stack ghc simple_calc2.hs
$ ./simple_calc2           
1 + 2
3
3 + 4
7
8 * 8
64
576308 (1) [Avatar] Offline
#3
This was my attempt: Thanks to 552234 for providing the missing piece. No idea why .
import Data.List.Split

type Symbol = Char

prepCalc :: String -> (Symbol,[String])
prepCalc str
  | add = ('+',splitOnSymbol)
  | mul = ('*',splitOnSymbol)
  where add = elem '+' str
        mul = elem '*' str
        splitOnSymbol = splitOneOf "+*" str

calc :: (Num a, Read a) => (Symbol,[String]) -> a
calc (symbol,(s1:s2:_))
  | symbol == '+' = i1 + i2
  | symbol == '*'  = i1 * i2
  where i1 = read s1
        i2 = read s2

main :: IO ()
main = do
   putStrLn "Add or multiply two numbers. e.g \"4+38\""
   userInput <- getContents

   let equationNoNewLine = lines $ userInput
   let value = map (calc . prepCalc) equationNoNewLine

   -- Was stuck here doing this
   -- print $ (show . head) value
   
   -- This fixed it. Thanks 552234.
   -- Be nice if someone can explain why it works.
   mapM_ print value