I want to check the condition of the previous if condition
to determine the next if condition
is to be executed or not. Each if condition
may return a value.
Edit: Sorry for that the example I provided before look a bit odd...:(
This is my real example, and I want to simplify the if-then-else
for goingToMove
goingToMove p routes points w h =
if canMove p points
-- the point can be moved in the map
then let r = routes ++ [p]
l = remainList p points
in move p r l w h
-- the point cannot be moved in the maps
else []
move p routes points w h =
if (length routes) == 2
then routes
else let one = goingToMove (tallRightCorner p) routes points w h in
if (null one)
then let two = goingToMove(tallRightBCorner p) routes points w h in
if (null two)
then let three = goingToMove (tallLeftBCorner p ) routes points w h in
if (null three)
then ....
...... -- until, let eight = ..
else three
else two
else one
Edit:Bad example When this thing is written in java, I may use a mutable boolean flag, and return a mutable data.
public String move (int number){
// base case
if (number == 0){
return "Finished the recursion";
}
// general case
else {
String result;
boolean isNull = false;
if ((result = move(3)) == null){
isNull = true;
}
else {
return result;
}
// continue to execute the if-conditions if the previous condition failed
if (isNull){
if((result = move(2)) == null){
isNull = true;
}
else {
return result;
}
}
if (isNull){
if((result = move(1)) == null){
isNull = true;
}
else {
return result;
}
}
return null;
}
}
But in Haskell, there is no mutable data, and only if-then-else
condition. Then the code will looks like this, and I want to simplify this because in my real work, there are 8 levels of if-then-else
which look terrible and messy....
move 0 = "Finished the recursion"
move n =
let one = move 3 in
if null one
then let two = move 2 in
if null two
then let three = move 1 in
then null
else three
else two
else one
In Haskell, multiple lines of if will be used by separating each of the if statement with its corresponding else statement. In the above example, we have introduced multiple conditions in one function. Depending on the function inputs, it will provide us different outputs.
No. However, you can have functions that return a trivial value.
return is actually just a simple function in Haskell. It does not return something. It wraps a value into a monad. Looks like return is an overloaded function.
In Java if I wanted to do the following:
result = func1(arg);
if (result == null){
result = func2(arg);
if (result == null){
result = func3(arg);
if (result == null){
result = func4(arg);
}
}
}
return result;
What I'm essentially doing is finding the first result from func1(args)
, func2(args)
, func3(args)
, func4(args)
that returns non-null.
In Haskell, I'd model func1
, func2
, func3
, and func4
as functions that returned a Maybe a
value, so that they could return Nothing
if they failed.
func1, func2, func3, func4 :: Int -> Maybe Result
Then I can use the <|>
operator (from Control.Applicative
), which has the following definition for Maybe a
:
Nothing <|> x = x
x <|> _ = x
So I can convert the above Java to
func1 arg <|> func2 arg <|> func3 arg <|> func4 arg
And due to the miracle of lazy evaluation, func2 arg
is only evaluated if func1 arg
returns Nothing
, same as in the Java example.
Apart from the nice employment of <|>
that rampion gave and the similar suggestion of sclv, another common way is to use guards, and exploit laziness,
move :: Int -> Maybe String
move n
| n == 0 = Just "Finished the recursion"
| isJust move3 = move3
| isJust move2 = move2
| isJust move1 = move1
| otherwise = Nothing
where
move3 = move 3
move2 = move 2
move1 = move 1
Due to laziness, move i
(i = 3, 2, 1
) is only evaluated if it's needed.
In the given case, move 3 <|> move 2 <|> move 1
is much nicer, but in cases where the conditions require evaluating different functions with different return types, the use of guards and lazy bindings in a where
clause can be the natural solution to avoid awkward nested if
s.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With