I would ideally like to write something like this:
myValue1 = 1 :: Int
myValue2 = 2 :: Int
myFunc :: Int -> Bool
myFunc myValue1 = True
myFunc myValue2 = False
Calling myFunc myValue2 returns True - not what I intend. I know why this happens, but is there a way to express this in Haskell without resorting to C-style #define statements?
Well, Haskell doesn't unify names like this. Those new 'myValue1' and '2' identifiers are new variables you're binding.
The most Haskelly way is to use strong types and pattern matching:
data Values
= D1
| D2
myFunc :: Values -> Bool
myFunc D1 = True
myFunc D2 = False
Giving you a static guarantee only "1" or "2" can be passed to myFunc, proper symbolic matching and you even retain conversion to integers by deriving Enum.
You cannot match against variable values as Don explained.
But you can use guards in this case:
myValue1 = 1 :: Int
myValue2 = 2 :: Int
myFunc :: Int -> Bool
myFunc x
| x == myValue1 = True
| x == myValue2 = False
If you don't want to create another data type, the usual solution is to use guards:
myValue1 = 1 :: Int
myValue2 = 2 :: Int
myFunc :: Int -> Bool
myFunc val | val == myValue1 = True
| val == myValue2 = False
What you put after the pipe can be any boolean condition; if it's true, the corresponding function body will be run.
If the idea is just to define some constants to use in patterns, you can also use the language extension PatternSynonyms:
{-# LANGUAGE PatternSynonyms #-}
pattern MyValue1 = 1
pattern MyValue2 = 2
myFunc :: Int -> Bool
myFunc MyValue1 = True
myFunc MyValue2 = False
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 have an algebraic data type like:
data Toll = Vok Int Bool | Bok Int | Cokd String Char
and another function
getVal :: Int -> Toll
getVal 1 = Cokd "hello" 'c'
getVal _ = Bok 12
I want to call getVal in some function and extract the arguments of Cokd (if the answer was of type Cokd) (maybe using pattern matching).
can I do like:
hello :: Int -> Bool
hello x = if st == "hell" then True else False
where (Cokd st ch) = getVal x
I cannot use monads.
How to do that?
You can use case to pattern-match the result of getVal:
data Toll = Vok Int Bool | Bok Int | Cokd String Char
getVal :: Int -> Toll
getVal 1 = Cokd "hello" 'c'
getVal _ = Bok 12
hello :: Int -> Bool
hello x =
case getVal x of
Cokd st ch ->
st == "hell"
_ -> False
Or create a separate function and pattern match the argument:
hello :: Int -> Bool
hello =
helloToll . getVal
where
helloToll (Cokd st ch) = st == "hell"
helloToll _ = False
The example, that you've provided in the question compiles (with few modifications), but it will throw a runtime exception when you try to call hello with 2 (or any other value different from 1, in which case getValue returns Bok 12, thus (Cokd st ch) = getVal x fails to pattern-match).
Your code seems totally fine, just one correction: the pattern if <expr> then True else False can be replaced with <expr>.
hello :: Int -> Bool
hello x = st == "hell" where (Cokd st ch) = getVal x
However, this code will fail for values other than 1 due to non-exhaustive pattern matching. You need to cover all cases:
hello :: Int -> Bool
hello x = case getVal x of
Cokd st ch -> st == "hell"
_ -> False
I'm going through type classes using this resource, I've come up with two uses:
a) Enabling functions to take different types without having to redefine the function interface:
class MyClass a where
myFunc :: a -> Bool
instance MyClass Int where
myFunc 1 = False
myFunc x = intFunction x
instance MyClass String where
myFunc "hello" = False
myFunc y = stringFunction
intFunction :: a -> Bool
intFunction i
| i > 100 = True
| otherwise = False
stringFunction :: a -> Bool
stringFunction s
| length s > 10 = False
| otherwise = True
b) Importing functionality into polymorphic functions:
class Operator a b where
(^&) :: a -> b -> Bool
instance Operator a b where
"hello" ^& 0 = True
x ^& y = False
exampleFunc :: (Operator a b) => a -> b -> Bool
exampleFunc e1 e2 = e1 ^& e2
Questions:
1) What are the other uses of type classes in Haskell?
2) How are type classes generally used in large programs?
N.B Apologies if this is a very broad question, I'm just trying to get a feel as to how I can structure my programs around type classes
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 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