2
\$\begingroup\$

I made a small program that tests numbers against some properties:

Welcome to Numbers!
Is it odd? 4
No
Is it a multiple of 18? 38
No
Is it big? 100
Yes

That's basically it :)

My code is:

import System.IO
import Text.Read

askUser :: String -> IO Double
askUser str = do
  putStr str
  num <- fmap readMaybe getLine

  case num of
    Nothing -> putStrLn "That is not a number!" >> askUser str
    Just num -> return num

numberCheck :: [Double] -> String -> IO ()
numberCheck list text = do
  num <- askUser ("Is it " ++ text ++ "? ")

  if num `elem` list
    then putStrLn "Yes"
    else putStrLn "No"


main :: IO ()
main = do
  hSetBuffering stdout NoBuffering
  putStrLn "Welcome to Numbers!"
  let alot = 99999

  let oddNum = take alot [x | x <- [0..], odd (round x)]
  numberCheck oddNum "odd"

  let multiples18 = take alot [x | x <- [0..], round x `mod` 18 == 0]
  numberCheck multiples18 "a multiple of 18"

  let bigNumbers = take alot [99..]
  numberCheck bigNumbers "big"

Is there anything that can be improved? I was especially thinking of the alot number, as it is not a "clean" way of solving this. But if I don't, Haskell will continue checking the list infinitely.

Is there any nicer way of achieving this?

Note: I used lists instead of comparisons because that's what I just learned, and so you can ignore me using lists if you want to :)

\$\endgroup\$

1 Answer 1

3
\$\begingroup\$

Integer not Double

Double is not a reasonable type because checking if a number is big does not work with Doubles, you should use Integer

First class functions

Using a list is not a clean procedure, it does not work for very big numbers and it is slow for big numbers.

It is better to pass in a validation function:

numberCheck :: (Integer -> Bool) -> String -> IO ()
numberCheck predicate text = do
  num <- askUser ("Is it " ++ text ++ "? ")

  if predicate num
    then putStrLn "Yes"
    else putStrLn "No"

Usage is:

main = do
  hSetBuffering stdout NoBuffering
  putStrLn "Welcome to Numbers!"

  numberCheck odd "odd"
  numberCheck (\x -> x `mod` 18 == 0) "multiple of 18"
  numberCheck (> 100) "big (bigger than 100)"
\$\endgroup\$
2
  • \$\begingroup\$ Thanks :) I actually only used list comprehensions because that's what I just learned ;). But why doesn't it work with Doubles? \$\endgroup\$
    – Rakete1111
    Sep 1, 2016 at 12:22
  • \$\begingroup\$ @Rakete1111 Is it big? 400.321 No Because a non-integer number is never contained in an integer range. \$\endgroup\$
    – Caridorc
    Sep 1, 2016 at 12:41

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.