Haskell alternative to long list of pattern matches? - haskell

I have a function that outputs a booleanlike property given a datatype. This function calculates the property by pattern matching on the first constructor of the datatype, so something like
data C = C1 | C2 | .. | Cn
f :: C -> Bool
f (C1 _ _ ... _) = True
f (C2 _ _ ... _) = True
f (C3 _ _ ... _) = False
.
.
.
f (Cn _ _ ..._) = False
Is there a more compact way to perform pattern-matching, or is there another (also more compact) way to go about my property checking? I prefer not to add the property to the data type definition since it can be calculated with relative ease.

You can avoid the wildcard patterns using record syntax. Also, use a case expression to avoid having to repeat the function name, e.g.
f :: C -> Bool
f x = case x of
C1 {} -> True
C2 {} -> False
...
Cn {} -> False
That's about as compact as it's going to get without changing your data type.

In addition, just list the Trueones or the False ones, depending on what you have less, and make the majority outcome a default:
f C1{} = True
f C42{} = True
f _ = False -- all others false

You might want to look at toConstr in the Data.Data module. This can give you a representation of the constructor, which you can then analyze as you wish (i.e. convert to a String, or get an index out of).

Building on #yatima's answer, you could do something like this
{-# LANGUAGE DeriveDataTypeable #-}
import Data.Char
import Data.Data
data C = C1 Int
| C2 Int
| C3 Int
| C4 Int
deriving (Data,Typeable)
f :: C -> Bool
f c = let [_,n] = show (toConstr c) in digitToInt n < 3
Then in GHCI
>> f (C1 0)
True
>> f (C2 0)
True
>> f (C3 0)
False
>> f (C4 0)
False

Perhaps:
f (x _ _ ... _) = g x where
g C1 = True
g C2 = True
g C3 = False
.
.
.
g Cn = False
You might be able to save a bit of typing using a case statement instead, but not much.
If we had more detail of the problem you were trying to solve (e.g. is there another representation for your data is there some pattern to the output) perhaps there's another approach.

Related

Merge multiple cases in Haskell

With a case _ of syntax like this:
fun a b c =
case (a, b, c) of
(Just True, Just _, _) -> foo
(Just True, _, Just _) -> foo
_ -> bar
Can I merge the first two conditions and avoid repeating foo?
Alternatively, is there any other (cleaner) way to express that I want to run foo if and only if a is Just True and either b or c are not Nothing?
You can do something like this:
fun a b c = case (a, b <|> c) of
(Just True, Just _) -> foo
_ -> bar
Of course, that's just hiding the extra match in (<|>), but you gotta pay the piper some time.
If b and c do not have the same type, you can cause them to with the ill-named void.
Let me complement the other answers with a "boring" alternative:
fun a b c = let
foo' = foo
in case (a, b, c) of
(Just True, Just _, _) -> foo'
(Just True, _, Just _) -> foo'
_ -> bar
This might or might not answer the intended question, depending on the actual goal.
If the goal was to avoid writing two patterns in the case, this of course fails to meet the goal.
If instead the goal was to avoid repeating foo, which could be a very long expression (e.g., a long do block in some monad), this meets the goal by giving a short name to the long expression.
Don't know if this looks cleaner but you could use the good old pal if too:
fun a b c =
if a == Just True && (isJust b || isJust c)
then foo
else bar
or use guards
fun a b c =
case a of
Just True | isJust b || isJust c -> foo
_ -> bar
without case:
fun (Just True) b c | isJust b || isJust c = foo
fun _ _ _ = bar
all is using isJust and as Daniel pointed out those too will give the piper it's due (pattern match).

Using filter with custom datatypes

I have these datatypes:
data Command = Back Int | Front Val deriving (Show,Eq)
data Val = Val {first::Int, second::Int, third::Int} deriving (Show, Eq)
type Program = [Command]
I have this function:
foo :: Program -> Int
foo list = length (filter (==Front Val {first, second, third}) list)
The purpose is to find how many times a Front occurs USING FILTER ONLY, and foo gives compilation error. I am not sure how to represent the integer/val part of Front.
You can not use an equality check (==) :: Eq a => a -> a -> Bool with variables like first and second, if these do not have a value. What you need here is pattern matching.
We can for example use list comprehension:
foo :: Program -> Int
foo list = length [ v | v#(Front _) <- list ]
There is no need to match the parameter with Val {}, or Val _ _ _, etc. since the only data constructor for the Val type is Val.
In case you think you will later add more data constructors, you can however add an extra subpattern:
foo :: Program -> Int
foo list = length [ v | v#(Front (Val {})) <- list ]
Or we can do the pattern matching in a function and use filter :: (a -> Bool) -> [a] -> [a], like:
foo :: Program -> Int
foo = length . filter f
where f (Front _) = True
f _ = False
or if we include the Val data constructor check:
foo :: Program -> Int
foo = length . filter f
where f (Front (Val {})) = True
f _ = False
As #WillemVanOnsem said in his answer, the approach you're using doesn't work. Try using filter (\x -> case x of { Front _ -> True; Back _ -> False }) list. You may be able to work out how this works from that alone, but if you need any more details:
\x -> case x of { Front _ -> True; Back _ -> False } is a lambda expression. It defines an unnamed (or anonymous) function which takes one parameter, named x, and returns the value given by case x of { Front _ -> True; Back _ -> False }.
case x of { Front _ -> True; Back _ -> False } does pattern matching on x. If x is of the form Front _, where _ can be anything, then it returns True; otherwise it returns False. Normally this statement would be formatted like this:
case x of
Front _ -> True
Back _ -> False
But the compact syntax above is shorter and so works better in this case.
The lambda expression above - which as discussed returns True when its argument is of the form Front _ - is then passed to filter as its argument.

Haskell instance Ord difficulties

I have a type that looks like this, and I would like the compare function to only take into account the size of the integer.
data Cell = FromLeft Coordinate Int
| FromTop Coordinate Int
| FromDiagonal Coordinate Int
| Empty Coordinate
deriving (Eq, Read, Show)
The following code works, but I would prefer something more elegant
instance Ord Cell where
compare (FromLeft _ x) (FromLeft _ y) = compare x y
compare (FromRight _ x) (FromLeft _ y) = compare x y
[...]
You could define an auxiliary function:
extractInt :: Cell -> Int
extractInt (FromLeft _ x) = x
extractInt (FromTop _ x) = x
extractInt (FromDiagonal _ x) = x
extractInt Empty = ???
and then
instance Ord Cell where
compare c1 c2 = compare (extractInt c1) (extractInt c2)
But be carefull: The above instance violates the antisymmetry law that states that if x<=y and y<=x then x==y. So it is not really defining an order but rather a preorder.

Count Number of Values Passed Into a Haskell Constructor

Suppose I have a data type
data Foo = Foo String Bool | Bar (String->Bool)
I want a function f that does:
f (Foo _ _) = [String, Bool]
f (Bar _) = [String->Bool]
In particular, I'd like this function to magically know that Foo and Boo are constructors, and not give me either of
f (Foo _ _) = [String -> Bool] -- #Don't want this!!!!
f (Boo _) = [String, Bool] -- #Don't want this!!!!
How can I do this? I know that I can print a list of records of an ADT using Data.Data, but I can't figure out how to print a list of typenames.
(If this is not possible, I would settle for a function f' that takes in ADTs and outputs whether or not it has 0 parameters.
f'(Foo _ _) = False
f'(Bar _) = False
I want this to work even if I don't assign records to the ADT f' operates on.)

Pattern-matching in case, Haskell

I'm fairly new to Haskell and have a question about pattern-matching.
Here is a heavily simplified version of the code:
data Value = MyBool Bool | MyInt Integer
codeDuplicate1 :: Value -> Value -> IO Value
codeDuplicate1 = generalFunction True
codeDuplicate2 :: Value -> Value -> IO Value
codeDuplicate2 = generalFunction False
generalFunction :: Bool -> Value -> Value -> IO Value
generalFunction b x1 x2 = do result <- eval x1
case result of
MyBool b -> do putStrLn $ show b
return (MyBool b)
_ -> eval x2
eval :: Value -> IO Value
eval (MyInt x) | x > 10 = return (MyInt 10)
| x > 5 = return (MyBool True)
| otherwise = return (MyBool False)
Now, I realize that the argument b in generalFunction is not the same as the b in the case part, and therefore, this code will print b regardless of the input. I used the same name just to show my intentions. So my question is:
Is there a way to match the first b with the second, so that if the bs are the same it will print, otherwise it will evaluate x2? And, if there isn't, is there another good way to get the intended result?
I almost found the answer in this question, but I think this situation is slightly different.
You can use a guarded pattern. The first alternative will be executed if MyBool is matched and b == b2; otherwise the second alternative will be executed.
case result of
MyBool b2 | b == b2 -> do {print b; return $ MyBool b}
_ -> eval x2

Resources