Using case for a multi-way if - haskell

Today, I found myself typing the following code:
case () of
_ | x < 15 -> ...
_ | x < 25 -> ...
_ | x < 50 -> ...
_ -> ...
The meaning of this is straight-forward enough, but it just feels... wrong to utter case (). Does anybody have a better suggestion?
I suppose since I'm branding on x, I could have written case x. But that still leaves me with nothing to actually pattern-match on; it's all about the guards. And that still feels weird.

There is nothing wrong with case (); it is the best you have for this use-case unless you want to use very recent syntactic and non-standard-extensions like GHC’s multi-way-if.

Others have mentioned that case if fine and mutli-way if exists, but I'd go for a local function via a where or let statement:
someFunction = do
x <- monadicOp
let f y | y < 5 = expr1
| y < 15 = expr2
| y < 25 = expr3
| True = expr4
f x
This is syntactically cleaner than the case statement solution and more portable than multi-way if.
EDIT:
In case it isn't clear, if the value being compared, x in this case, is already in scope when you define the guarded function (f) then you could just define a value instead:
someFunction = do
x <- monadicOp
let r | x < 15 = expr1
| x < 25 = expr2
r

You can exploit lazy evaluation to come up with something like this:
import Data.List
import Data.Maybe
import Control.Applicative
cases :: [(Bool,a)] -> a -> a
cases lst d = snd $ fromJust $ (find fst lst) <|> Just (True,d)
main = do
let x = 20
r = cases [(x < 15, putStr "15"),
(x < 25, putStr "25"),
(x < 50, putStr "50")] $ putStr "None"
in
r

Related

whats the advantage of using guards in Haskell?

count_instances :: (Int)->([Int])->Int
count_instances x [] = 0
count_instances x (t:ts)
| x==t = 1+(count_instances x ts)
| otherwise = count_instances x ts
i just want to know whats so good about using guards in this Question ?
A guard can be a way to write only one half of an if-then-else expression; you can omit the else and have a partial function.
-- Leave the function undefined for x /= y
foo x y | x == y = ...
You can do the same with a case statement, but it's more verbose
foo x y = case x == y of
True -> ...
It's also easier to list several unrelated conditions as a set of alternatives than it is with a nested if-then-else or case expressions.
foo x y | p1 x y = ...
foo x y | p2 x y = ...
foo x y | p3 x y = ...
foo x y = ...
vs
foo x y = if p1 x y then ...
else (if p2 x y then ...
else (if p3 x y then ... else ...))
Patterns with guards are probably the most concise way to write code that otherwise would require nested case/if expressions.
Not the least advantage is that a where clause applies to all the guards right hand sides. This is why your example could be even more concise:
count_instances :: (Int)->([Int])->Int
count_instances x [] = 0
count_instances x (t:ts)
| x==t = 1+rest
| otherwise = rest
where rest = count_instances x ts
A guard is haskell's most general conditional statement, like if/then/else in other languages.
Your code shows a straight forward implementation of counting contents of a list equal to a given parameter. This is a good example to learn how haskell's recursion works.
An alternative implementation would be
count_instances :: Int -> [Int] -> Int
count_instances i = length . filter (==i)
that reuses already existing functions from the Prelude module. This is shorter and probably more readable.

Just Int to Int

This code either returns the first factor of an Integer starting from 2 or returns nothing if it's a prime.
Example: firstFactorOf 24 returns "Just 2"
Example: firstFactorOf 11 returns "Nothing"
My question is, how would I return the value 2 rather than "Just 2" if there is a factor or return the value x if there is no factor.
firstFactorOf x
| m == Nothing = m
| otherwise = m
where m =(find p [2..x-1])
p y = mod x y == 0
//RETURNS:
ghci> firstFactorOf 24
Just 2
ghci> firstFactorOf 11
Nothing
Haskell is statically typed, meaning that you can define a function Maybe a -> a, but the question is what to do with the Nothing case.
Haskell has two functions that can be helpful here: fromMaybe and fromJust:
fromMaybe :: a -> Maybe a -> a
fromJust :: Maybe a -> a
fromJust simply assumes that you will always provide it a Just x, and return x, in the other case, it will throw an exception.
fromMaybe on the other hand expects two parameters, the first - an a is the "default case" the value that should be returned in case of Nothing. Next it is given a Maybe a and in case it is a Just x, x is returned. In the other case (Nothing) as said before the default is returned.
In your comment you say x should be returned in case no such factor exists. So I propose you define a new function:
firstFactorOfJust :: Integral a => a -> a
firstFactorOfJust x = fromMaybe x $ firstFactorOf x
So this function firstFactorOfJust calls your firstFactorOf function and if the result is Nothing, x will be returned. In the other case, the outcome of firstFactorOf will be returned (but only the Integral part, not the Just ... part).
EDIT (simplified)
Based on your own answer that had the intend to simplify things a bit, I had the idea that you can simplify it a bit more:
firstFactorOf x | Just z <- find ((0 ==) . mod x) [2..x-1] = z
| otherwise = x
and since we are all fan of optimization, you can already stop after sqrt(x) iterations (a well known optimization in prime checking):
isqrt :: Int -> Int
isqrt = floor . sqrt . fromIntegral
firstFactorOf x | Just z <- find ((0 ==) . mod x) [2..isqrt x] = z
| otherwise = x
Simplified question
For some reason there was some peculiarly complicated aspect in your question:
firstFactorOf x
| m == Nothing = m
| otherwise = m
where m =(find p [2..x-1])
p y = mod x y == 0
Why do you use guards to make a distinction between two cases that generate the exact same output? You can fold this into:
firstFactorOf x = m
where m = (find p [2..x-1])
p y = mod x y == 0
and even further:
firstFactorOf x = find p [2..x-1]
where p y = mod x y == 0
If you want it to return the first factor of x, or x, then this should work:
firstFactorOf x =
let
p y = mod x y == 0
m = (find p [2..x-1])
in
fromMaybe x m
import Data.List
import Data.Maybe
firstFactorOf x
| m == Nothing = x
| otherwise = fromJust m
where m =(find p [2..x-1])
p y = mod x y == 0
This was what I was after. Not sure why you guys made this so complicated.

haskell : How to report an error for my function

this is an expansion to my last question here: basic haskell : Copying elements
however when an invalid input is added then I want it to print out an error message saying "negative value" or something similar. Is this possible in haskell?
working code:
copy :: Int->a->[a]
copy 0 _ = []
copy y a = [a]++(copy (y-1) a)
final line:
copy b c = error "negative value"
Because partial functions make me sad, I'd suggest doing something more along the lines of
copy :: Int -> a -> Maybe [a]
copy 0 _ = Just []
copy n a | n < 0 = Nothing
| otherwise = fmap (a:) (copy (n-1) a)
We've swapped out that if for a "guard"
foo bar | baz = quux
| ...
is just
foo bar = if baz then quux else ...
Note that I also changed your code a little,
[a] ++ copy (y-1) a ====> fmap (a:) (copy (y-1) a)
You can think of (:) as append.
1 : [2, 3] ==> [1, 2, 3]
It's the preferred alternative to [1] ++ [2, 3]. Say it out loud as "cons", like "construct". We can write this with an operator section
(a:) ==> \x -> a : x
Next we use this wonky fmap function. Think of fmap like this
fmap f Nothing = Nothing
fmap f (Just x) = Just (f x)
So it unwraps a Just and applies a function before rewrapping the result. So our final code returns Nothing if our number is negative, otherwise, just the list.
Why aren't I recommending error? Well because error will blow up your whole program with pretty minimal information and it's a bad idea to try to catch it. Haskell doesn't even mandate that it's possible to do so, GHC just implements error in such a way that it's possible. In other words, you have little chance to recover.
This isn't a big deal for 10 lines of code, but I've spent upwards of 6 hours searching for the offending call to a function using error. It's much faster to debug and more idiomatic haskell.
You can do this with guards
copy :: Int -> a -> [a]
copy n x
| n < 0 = error "negative value"
| n == 0 = []
| otherwise = x : copy (n - 1) x
However, if this fails then it will likely crash your program. A better way is to use the Maybe type:
copySafe :: Int -> a -> Maybe [a]
copySafe n x
| n < 0 = Nothing
| otherwise = Just (copy n x)
Then you can use it as
main = do
putStrLn "Enter a number:"
nStr <- getLine
let n = read nStr :: Int
maybeXs = copySafe n n
case maybeXs of
Nothing -> putStrLn "You entered a negative number!"
Just xs -> print xs
This style forces you to consider both cases of copySafe, either it can fail on a negative value or it can return a valid list. It doesn't crash your program and the error handling is enforced by the type system.
look at http://www.haskell.org/haskellwiki/Error_vs._Exception
for example
copy b c = if c > b then error "negativ value"

how can i use more guards with small tricks?

When i compile my code in ghci, there is no problem. It can compile correctly. However, if i try to compile it in hugs, I get the error "compiled code too complex". I think the problem is due to many | conditions.
If I change it to use if/else, there is no problem. I can add if/else statements 100 times but this will be very tiresome and annoying. Rather than that, I tried to put if/else statements after 20-30 | conditions, but i cannot make | work inside if statements like the below:
f x y z
| cond1 = e1
| cond2 = e2
...
if (1)
then
| cond30 = e30
| cond31 = e31
...
else
| cond61 = e61
| cond62 = e62
How can I fix the code with the least effort? The complete code is on hpaste because it is longer than StackOverflow's question size limit.
Avoiding repetitive guards
Firstly, you can rewrite
function input
| this && that && third thing && something else = ... -- you only actually needed brackets for (head xs)
| this && that && third thing && something different = ....
| this && that && a change && ...
...
| notthis && ....
with
function input | this = function2 input'
| notthis = function4 input'
function2 input | that = function3 input''
| notthat = ...
That should simplify your 200 lines of copo code down, but it's still the wrong approach.
Use a function to deal with the same problem just once, not every time
The 4 cases for dealing with operations that you deal with time after time could be replaced with one function, perhaps like:
operation :: Num a => Char -> a -> a -> a
operation x = case x of
'+' -> (+)
'-' -> (-)
'*' -> (*)
'/' -> (/)
_ -> error ("operation: expected an operation (+-*/) but got " ++ [c])
Use list functions instead of testing characters one at a time
You should use some standard functions to help reduce all the single character checks into just grabbing as much number as is there. takeWhile :: (a -> Bool) -> [a] -> [a], so
takeWhile isDigit "354*243" = "354"
takeWhile isDigit "+245" = ""
and there's the corresponding dropWhile:
dropWhile isDigit "354*1111" = "*1111"
dropWhile isDigit "*1111" = "*1111"
So the most dramatic shortening of your code would be to start copo with
copo xs = let
numText = takeWhile isDigit xs
theRest = droWhile isDigit xs
num = read numText
....
in answer....
but there's a shortcut if you want both takeWhile and dropWhile, called span, because span p xs == (takeWhile p xs, dropWhile p xs)
copo xs = let
(numText,theRest) = span isDigit xs
num = read numText
....
in answer....
Use recursion instead of repeating code
You deal with 234 then 234*56 then 234*56/23 then ....
You could replace this with a recursive call to copo, or produce a tree. This depends on whether you're supposed to obey the normal operator precedence (* or / before + or -) or not.
If you insist on guards, instead of
foo a b c d
| cond1, cond2, cond3 = ...
| cond1, cond2, cond4 = ...
| cond5, cond6, cond7 = ...
| cond5, cond6, cond8 = ...
write
foo a b c d
| cond1, cond2 = case () of
() | cond3 = ...
| cond4 = ...
| cond5, cond6 = case () of
() | cond7 = ...
| cond8 = ...

Haskell syntax for 'or' in case expressions

In F#, I can use | to group cases when pattern matching. For example,
let rec factorial n =
match n with
| 0 | 1 -> 1 // like in this line
| _ -> n * factorial (n - 1)
What's the Haskell syntax for the same?
There is no way of sharing the same right hand side for different patterns. However, you can usually get around this by using guards instead of patterns, for example with elem.
foo x | x `elem` [A, C, G] = ...
| x `elem` [B, D, E] = ...
| otherwise = ...
with guards:
factorial n
| n < 2 = 1
| otherwise = n * (factorial (n - 1))
with pattern matching:
factorial 0 = 1
factorial 1 = 1
factorial n = n * (factorial (n - 1))
I'm not entirely familiar with F#, but in Haskell, case statements allow you to pattern match, binding variables to parts of an expression.
case listExpr of
(x:y:_) -> x+y
[x] -> x
_ -> 0
In the theoretical case that Haskell allowed the same:
It would therefore be problematic to allow multiple bindings
case listExpr of
(x:y:_) | [z] -> erm...which variables are bound? x and y? or z?
There are rare circumstances where it could work, by using the same binding:
unEither :: Either a a -> a
unEither val = case val of
Left v | Right v -> v
And as in the example you gave, it could work alright if you only match literals and do not bind anything:
case expr of
1 | 0 -> foo
_ -> bar
However:
As far as I know, Haskell does not have syntax like that. It does have guards, though, as mentioned by others.
Also note:
Using | in the case statement serves a different function in Haskell. The statement after the | acts as a guard.
case expr of
[x] | x < 2 -> 2
[x] -> 3
_ -> 4
So if this sort of syntax were to be introduced into Haskell, it would have to use something other than |. I would suggest using , (to whomever might feel like adding this to the Haskell spec.)
unEither val = case val of
Left v, Right v -> v
This currently produces "parse error on input ,"
Building on some of the above answers, you can (at least now) use guards to do multiple cases on a single line:
case name of
x | elem x ["Bob","John","Joe"] -> putStrLn "ok!"
"Frank" -> putStrLn "not ok!"
_ -> putStrLn "bad input!"
So, an input of "Bob", "John", or "Joe" would give you an "ok!", whereas "Frank" would be "not ok!", and everything else would be "bad input!"
Here's a fairly literal translation:
factorial n = case n of
0 -> sharedImpl
1 -> sharedImpl
n -> n * factorial (n - 1)
where
sharedImpl = 1
View patterns could also give you a literal translation.
isZeroOrOne n = case n of
0 -> True
1 -> True
_ -> False
factorial1 n = case n of
(isZeroOrOne -> True) -> 1
n -> n * factorial (n - 1)
factorial2 n = case n of
(\n -> case n of { 0 -> True; 1 -> True; _ -> False }) -> 1
n -> n * factorial (n - 1)
Not saying that these are better than the alternatives. Just pointing them out.

Resources