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).
Related
I have some function test which has a signature like:
data D = D | C
test :: D -> ....
test d ... =
And I want to create with let some nested function which body is either body-A or body-B based on case analyze of the d. So, I can do it as:
let nestedFun p =
case d of
C -> case (ft, p) of
(Just SM.FileTypeRegular, Just p1) | Just nm <- takeFileName (cs p1) -> S.member nm itemNames
_ -> False
D -> case (ft, p) of
(Just SM.FileTypeRegular, Just p1) -> S.member (hash $ cs #_ #FilePath p1) itemHashes
_ -> False
or as
let nestedFun p =
case (ft, p) of
(Just SM.FileTypeRegular, Just p1) -> case d of
C | Just nm <- takeFileName (cs p1) ->
S.member nm itemNames
D ->
S.member (hash $ cs #_ #FilePath p1) itemHashes
_ -> False
In short, the difference is that the 1st version looks like Python's:
if isinstance(d, D):
nestedFun = lambda p: ...
else:
nestedFun = lambda p: ...
while the 2nd one is like:
def nestedFun(p):
if isinstance(d, D): ...
else: ...
I will call this nestedFun on the big list of values so the question here is: Is the Haskell compiler/optimizer able to understand that both versions are the same and to reduce the 2nd one to the 1st one, so the case-analyze on d happens just once?
GHC is able to -- the optimizer does consider case-of-case transformations to see if they enable other optimizations -- but not in a way that you can rely on. If you need this, I highly recommend performing that transformation by hand. In fact, for the case you describe here, I would go even farther, and make it clear that the case can happen before p is in scope:
nestedFunDmwit = case d of
C -> \p -> case (ft, p) of ...
D -> \p -> case (ft, p) of ...
The difference here is that nestedFun will re-evaluate the case each time it is applied to an argument, while nestedFunDmwit will evaluate the case just once. So, for example, map (nestedFun x) [a, b, c] would reliably evaluate the case just once; map nestedFun [a, b, c] would evaluate the case three times unless things line up just so for the optimizer; and map nestedFunDmwit [a, b, c] would reliably evaluate the case just once.
Why does this function always succeed? It always returns True with any values and any types. Is this the correct behavior?
f a b = case a of b -> True; _ -> False
The b in the case definition is not the b in in the head of the f definition. You created a new locally scoped variable. Your code is thus equivalent to:
f a b = case a of
c -> True
_ -> False
Pattern matching with a variable indeed always succeeds.
If you want to check if two values are the same, you will need to define some function (or let Haskell automatically derive Eq for example).
Note: you can turn on the -Wname-shadowing warning to let the compiler warn you about creating identifiers that shadow existing ones. For example your code will produce:
Prelude> f a b = case a of b -> True; _ -> False
<interactive>:1:19: warning: [-Wname-shadowing]
This binding for ‘b’ shadows the existing binding
bound at <interactive>:1:5
Just in addition to the perfect answer accepted, my two cents:
this:
f a b = case a of b -> True; _ -> False -- (A)
and this:
f a b = case a of
c -> True
_ -> False --(B)
are is equivalent to:
f a b = case a of
_ -> True
or
f a b = True
or
f _ b = True
So, be careful because that's the real behavior you created, a function that takes two parameters and returns always True.
Also:
(A) and (B) will show this warning if -Woverlapping-patterns is used:
warning: [-Woverlapping-patterns]
Pattern match is redundant
In a case alternative: _ -> ...
|
3 | _ -> False
| ^^^^^^^^^^
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.
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.)
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