Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

NILL value in haskell

Tags:

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

like image 802
gruber Avatar asked May 28 '10 23:05

gruber


2 Answers

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

like image 159
Norman Ramsey Avatar answered Sep 30 '22 00:09

Norman Ramsey


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.

like image 44
MtnViewMark Avatar answered Sep 30 '22 00:09

MtnViewMark