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
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.)
In this case, Maybe may not suffice: You have three conditions to worry about:
The user entered nothing
The user input was valid
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.
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"
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
Related
Let us say we have
data D = X Int | Y Int Int | Z String
I wish to have a function getDConst
getDConst :: D -> String
that returns either "X", "Y", or "Z", according to the data constructor used for its input. Is there a generic way to write this without having to do case on every data constructor? (I am ok with solutions relying on Data.Typeable or something similar)
Found the solution myself, but leaving this question to help others:
import Data.Data
data D = X Int | Y Int Int deriving (Data,Typeable)
let result = show $ toConstr (X 3) -- result contains what we wanted
If you don't want to use Typeable, you can also do this with Show.
getDConst :: D -> String
getDConst = head . words . show
Show will not output all the fields, because it is lazy. You can test it runing this code in ghci:
Prelude> data D = D [Int] deriving (Show)
Prelude> getDConst $ D [1..]
"D"
I have a much basic answer to the question without going through imports or whatever. It's Just a simple mere function.
let's say I have the following data. The repetitive Int in the data definition is intentional because I will use the don't care symbol afterwards:
data YES_NO_CANCEL = YES Int | NO Int Int | CANCEL Int Int Int
then you can make a function as :
extractDataType :: YES_NO_CANCEL -> String
extractDataType (YES _) = "YES"
extractDataType (NO _ _) = "NO"
extractDataType (CANCEL _ _ _) = "CANCEL"
I want to write a function that gets the first integer in a string, if the integer is at the beginning of the string and is followed by space or nothing.
For example, "12" and "12 kids" would be valid strings, but "12kids", "a12" are invalid.
This is my function:
getFirstInteger :: String -> Int
getFirstInteger [] = error "No integer"
getFirstInteger str
| dropWhile (Char.isNumber) str == [] = read str :: Int
| Char.isSpace $ head $ dropWhile (Char.isNumber) str = read (takeWhile (Char.isNumber) str) :: Int
| otherwise = error "No integer found"
The problem is that if the string is actually an integer, head will raise an exception, so that is why the first condition exists. Is there any elegant solution to this problem?
getFirstInteger :: String -> Int
getFirstInteger = read . head . words
words will split the String into a list of Strings, which were originally separated by whitespace. head will take the first (or error if the original string was empty), and read will parse the string as usual (and error if the first word wasn't a valid Int).
However, I prefer a variant that doesn't use error on empty Strings or unparseable ones, e.g.
import Text.Read (readMaybe)
getFirstInteger :: String -> Maybe Int
getFirstInteger [] = Nothing
getFirstInteger xs = readMaybe . head . words $ xs
One could write this completely point-free with listToMaybe from Data.Maybe, but that's probably an overkill:
import Data.Maybe (listToMaybe)
import Text.Read (readMaybe)
import Control.Monad ((>=>))
getFirstInteger :: String -> Maybe Int
getFirstInteger = listToMaybe . words >=> readMaybe
If you want to parse strings without using parser combinator libraries or any of the machinery in Text.Read, have a look at the functions break and span:
span :: (a -> Bool) -> [a] -> ([a], [a])
break :: (a -> Bool) -> [a] -> ([a], [a])
The nice thing is that both of these functions not only return what they match but also the remainder of the string allowing you to continue your parsing.
To solve your problem:
import Data.Char
getFirstInteger :: String -> Maybe Int
getFirstInteger str
let (digs, rest1) = span isDigit str
endsok = case rest1 of
[] -> True
(c:_) -> c == ' '
in
if not (null digs) && endsok
then Just (read digs)
else Nothing -- either no digits or doesn't end properly
This version does not allow a leading minus sign. This next version allows an optional leading minus sign for the integer:
getFirstInteger' str =
let (minus,rest1) = span (=='-') str
(digs, rest2) = span isDigit rest1
endsok = case rest2 of
[] -> True
(c:_) -> c == ' '
in
if length minus <= 1 && not (null digs) && endsok
then Just (read (minus ++ digs))
else Nothing
Yes - this does not terminate as early as possible on bad input. I provide it mainly as an example of how to chain together calls to span and break.
Use reads. For example:
type Unit = String
readUnit :: String -> Maybe (Int, Maybe Unit)
readUnit s = case reads s of -- the integer is at the beginning of the string and...
(n, ' ':unit):_ -> Just (n, Just unit) -- is followed by space...
(n, "" ):_ -> Just (n, Nothing) -- or nothing.
_ -> Nothing
In ghci:
> readUnit "12"
Just (12,Nothing)
> readUnit "12 kids"
Just (12,Just "kids")
> readUnit "12kids"
Nothing
> readUnit "a12"
Nothing
However, there are a few minor considerations to keep in mind. It's possible that read does not restrict the syntax as much as you might want; for example, the following answer may surprise you:
> readUnit " ((-0x5)) kids"
Just (-5,Just "kids")
You may also want to drop extraneous spaces in the unit; for example, you could change the first clause above to
(n, ' ':unit):_ -> Just (n, Just (dropWhile isSpace unit))
or similar. And as a final variation on this theme, note that while the standard instances of Read never return lists with more than one element from reads, it is technically possible that some user-supplied type may do so. So if you were ever to use reads to parse types other than Int, you may want to either demand an unambiguous parse or consider all the parses before deciding what to do; the above code bakes in the assumption that the first parse is as good as any.
Im working through the exercises on wikibooks/haskell and there is an exercise in the MonadPlus-chapter that wants you to write this hexChar function. My function works as shown below, but the thing is that when I try to switch the 2 helper parsers (digitParse and alphaParse) around the function ceases to work properly. If I switch them around I can only parse digits and not alphabetic chars anymore.
Why is this so?
char :: Char -> String -> Maybe (Char, String)
char c s = do
let (c':s') = s
if c == c' then Just (c, s') else Nothing
digit :: Int -> String -> Maybe Int
digit i s | i > 9 || i < 0 = Nothing
| otherwise = do
let (c:_) = s
if read [c] == i then Just i else Nothing
hexChar :: String -> Maybe (Char, String)
hexChar s = alphaParse s `mplus` digitParse s -- cannot switch these to parsers around!!
where alphaParse s = msum $ map ($ s) (map char (['a'..'f'] ++ ['A'..'F']))
digitParse s = do let (c':s') = s
x <- msum $ map ($ s) (map digit [0..9])
return (intToDigit x, s')
if read [c] == i then Just i else Nothing
The marked code has a flaw. You're using Int's Read instance, e.g. read :: String -> Int. But if it's not possible to parse [c] as an int (e.g. "a"), read will throw an exception:
> digit 1 "doesnt start with a digit"
*** Exception: Prelude.read: no parse
> -- other example
> (read :: String -> Int) "a"
*** Exception: Prelude.read: no parse
Instead, go the other way:
if [c] == show i then Just i else Nothing
This will always works, since show won't fail (not counting cases where bottom is involved).
I use System.Random and System.Random.Shuffle to shuffle the order of characters in a string, I shuffle it using:
shuffle' string (length string) g
g being a getStdGen.
Now the problem is that the shuffle can result in an order that's identical to the original order, resulting in a string that isn't really shuffled, so when this happens I want to just shuffle it recursively until it hits a a shuffled string that's not the original string (which should usually happen on the first or second try), but this means I need to create a new random number generator on each recursion so it wont just shuffle it exactly the same way every time.
But how do I do that? Defining a
newg = newStdGen
in "where", and using it results in:
Jumble.hs:20:14:
Could not deduce (RandomGen (IO StdGen))
arising from a use of shuffle'
from the context (Eq a)
bound by the inferred type of
shuffleString :: Eq a => IO StdGen -> [a] -> [a]
at Jumble.hs:(15,1)-(22,18)
Possible fix:
add an instance declaration for (RandomGen (IO StdGen))
In the expression: shuffle' string (length string) g
In an equation for `shuffled':
shuffled = shuffle' string (length string) g
In an equation for `shuffleString':
shuffleString g string
= if shuffled == original then
shuffleString newg shuffled
else
shuffled
where
shuffled = shuffle' string (length string) g
original = string
newg = newStdGen
Jumble.hs:38:30:
Couldn't match expected type `IO StdGen' with actual type `StdGen'
In the first argument of `jumble', namely `g'
In the first argument of `map', namely `(jumble g)'
In the expression: (map (jumble g) word_list)
I'm very new to Haskell and functional programming in general and have only learned the basics, one thing that might be relevant which I don't know yet is the difference between "x = value", "x <- value", and "let x = value".
Complete code:
import System.Random
import System.Random.Shuffle
middle :: [Char] -> [Char]
middle word
| length word >= 4 = (init (tail word))
| otherwise = word
shuffleString g string =
if shuffled == original
then shuffleString g shuffled
else shuffled
where
shuffled = shuffle' string (length string) g
original = string
jumble g word
| length word >= 4 = h ++ m ++ l
| otherwise = word
where
h = [(head word)]
m = (shuffleString g (middle word))
l = [(last word)]
main = do
g <- getStdGen
putStrLn "Hello, what would you like to jumble?"
text <- getLine
-- let text = "Example text"
let word_list = words text
let jumbled = (map (jumble g) word_list)
let output = unwords jumbled
putStrLn output
This is pretty simple, you know that g has type StdGen, which is an instance of the RandomGen typeclass. The RandomGen typeclass has the functions next :: g -> (Int, g), genRange :: g -> (Int, Int), and split :: g -> (g, g). Two of these functions return a new random generator, namely next and split. For your purposes, you can use either quite easily to get a new generator, but I would just recommend using next for simplicity. You could rewrite your shuffleString function to something like
shuffleString :: RandomGen g => g -> String -> String
shuffleString g string =
if shuffled == original
then shuffleString (snd $ next g) shuffled
else shuffled
where
shuffled = shuffle' string (length string) g
original = string
End of answer to this question
One thing that might be relevant which I don't know yet is the difference between "x = value", "x <- value", and "let x = value".
These three different forms of assignment are used in different contexts. At the top level of your code, you can define functions and values using the simple x = value syntax. These statements are not being "executed" inside any context other than the current module, and most people would find it pedantic to have to write
module Main where
let main :: IO ()
main = do
putStrLn "Hello, World"
putStrLn "Exiting now"
since there isn't any ambiguity at this level. It also helps to delimit this context since it is only at the top level that you can declare data types, type aliases, and type classes, these can not be declared inside functions.
The second form, let x = value, actually comes in two variants, the let x = value in <expr> inside pure functions, and simply let x = value inside monadic functions (do notation). For example:
myFunc :: Int -> Int
myFunc x =
let y = x + 2
z = y * y
in z * z
Lets you store intermediate results, so you get a faster execution than
myFuncBad :: Int -> Int
myFuncBad x = (x + 2) * (x + 2) * (x + 2) * (x + 2)
But the former is also equivalent to
myFunc :: Int -> Int
myFunc x = z * z
where
y = x + 2
z = y * y
There are subtle difference between let ... in ... and where ..., but you don't need to worry about it at this point, other than the following is only possible using let ... in ..., not where ...:
myFunc x = (\y -> let z = y * y in z * z) (x + 2)
The let ... syntax (without the in ...) is used only in monadic do notation to perform much the same purpose, but usually using values bound inside it:
something :: IO Int
something = do
putStr "Enter an int: "
x <- getLine
let y = myFunc (read x)
return (y * y)
This simply allows y to be available to all proceeding statements in the function, and the in ... part is not needed because it's not ambiguous at this point.
The final form of x <- value is used especially in monadic do notation, and is specifically for extracting a value out of its monadic context. That may sound complicated, so here's a simple example. Take the function getLine. It has the type IO String, meaning it performs an IO action that returns a String. The types IO String and String are not the same, you can't call length getLine, because length doesn't work for IO String, but it does for String. However, we frequently want that String value inside the IO context, without having to worry about it being wrapped in the IO monad. This is what the <- is for. In this function
main = do
line <- getLine
print (length line)
getLine still has the type IO String, but line now has the type String, and can be fed into functions that expect a String. Whenever you see x <- something, the something is a monadic context, and x is the value being extracted from that context.
So why does Haskell have so many different ways of defining values? It all comes down to its type system, which tries really hard to ensure that you can't accidentally launch the missiles, or corrupt a file system, or do something you didn't really intend to do. It also helps to visually separate what is an action, and what is a computation in source code, so that at a glance you can tell if an action is being performed or not. It does take a while to get used to, and there are probably valid arguments that it could be simplified, but changing anything would also break backwards compatibility.
And that concludes today's episode of Way Too Much Information(tm)
(Note: To other readers, if I've said something incorrect or potentially misleading, please feel free to edit or leave a comment pointing out the mistake. I don't pretend to be perfect in my descriptions of Haskell syntax.)
Let us say we have
data D = X Int | Y Int Int | Z String
I wish to have a function getDConst
getDConst :: D -> String
that returns either "X", "Y", or "Z", according to the data constructor used for its input. Is there a generic way to write this without having to do case on every data constructor? (I am ok with solutions relying on Data.Typeable or something similar)
Found the solution myself, but leaving this question to help others:
import Data.Data
data D = X Int | Y Int Int deriving (Data,Typeable)
let result = show $ toConstr (X 3) -- result contains what we wanted
If you don't want to use Typeable, you can also do this with Show.
getDConst :: D -> String
getDConst = head . words . show
Show will not output all the fields, because it is lazy. You can test it runing this code in ghci:
Prelude> data D = D [Int] deriving (Show)
Prelude> getDConst $ D [1..]
"D"
I have a much basic answer to the question without going through imports or whatever. It's Just a simple mere function.
let's say I have the following data. The repetitive Int in the data definition is intentional because I will use the don't care symbol afterwards:
data YES_NO_CANCEL = YES Int | NO Int Int | CANCEL Int Int Int
then you can make a function as :
extractDataType :: YES_NO_CANCEL -> String
extractDataType (YES _) = "YES"
extractDataType (NO _ _) = "NO"
extractDataType (CANCEL _ _ _) = "CANCEL"