gruber
gruber

Reputation: 29789

NILL value in haskell

I get input (x) from user, convert it to Int by let y = (read x)::Int and then I would like the function to behave in a special way if user gave nothing (empty string).

-- In this place I would like to handle situation in which user
-- gave empty string as argument
-- this doesnt work :/
yearFilter [] y = True

--This works fine as far as y is integer
yearFilter x y  | x == (objectYear y) = True
                | otherwise = False

Thanks for help, Bye

Upvotes: 5

Views: 6184

Answers (4)

MtnViewMark
MtnViewMark

Reputation: 5150

In this case, Maybe may not suffice: You have three conditions to worry about:

  1. The user entered nothing
  2. The user input was valid
  3. The user input was unparsable

This data type and function express this directly:

data Input a = NoInput | Input a |  BadInput String
    deriving (Eq, Show)

input :: (Read a) => String -> Input a
input "" = NoInput
input s =
    case filter (null.snd) (reads s) of
        ((a,_):_) -> Input a
        otherwise -> BadInput s

Note that rather than using the incomplete function read, it uses reads which will not error on input which cannot be converted. reads has a somewhat awkward interface, alas, so I almost always end up wrapping it in a function that returns Maybe a or something like this here.

Example use:

> input "42" :: Input Int
Input 42
> input "cat" :: Input Int
BadInput "cat"
> input "" :: Input Int
NoInput

I would code your yearFilter function like this:

yearFilter :: Maybe Int -> Int -> Bool
yearFilter Nothing  _ = True
yearFilter (Just x) y = x == objectYear y

Then I'd handle user input as:

inputToMaybe :: Input a -> Maybe a
inputToMaybe (Input a) = Just a
inputToMaybe _         = Nothing

do
    a <- input `fmap` getLine
    case a of
        BadInput s -> putStrLn ("Didn't understand " ++ show s)
        otherwise  -> ... yearFilter (inputToMaybe a) ....

N.B.: I've cleaned up the code in yearFilter a bit: no need to use guards to produce a boolean from a test - just return the test, function application (objectYear) binds tighter than operators (==) so removed parenthesis, replaced names of unused inputs with _.


Okay, I admit I can't help myself.... I've rewritten yearFilter yet again, this time as I would be inclined to write it:

yearFilter :: Maybe Int -> Int -> Bool
yearFilter x y = maybe True (== objectYear y) x

Learning about Maybe and maybe was first thing about Haskell that really made me love the language.

Upvotes: 4

Norman Ramsey
Norman Ramsey

Reputation: 202725

Perhaps you want a Maybe type? If the user enters the empty string, your function returns Nothing; otherwise it returns Just n, where n is what's entered by the user?

userInt :: String -> Maybe Int
userInt [] = Nothing
userInt s  = Just $ read s

(I haven't compiled this code.)

Upvotes: 14

Daniel Pratt
Daniel Pratt

Reputation: 12077

The 'read' function cannot convert an empty string to an int, and will cause an error if you try to do so. You'll need to test whether the input is an empty string before converting to int. If you want to use a default value (such as 0) in the event that the user enters an empty string, you could do something like this:

let y = if null x then 0 else read x

Upvotes: 2

chmod222
chmod222

Reputation: 5722

There is no NULL unless you explicitly define it. You could check for empty strings like this.

readInput :: IO ()
readInput = do
   ln <- getLine
   if valid ln
      then -- whatever
      else -- whatever

valid x
    | null x                = False
    | not istJust convert x = False
    | otherwise             = True
where convert :: String -> Maybe Int
      convert = fmap fst $ listToMaybe  . reads $ "f"

Upvotes: 3

Related Questions