[英]How to simplify nested-if using to return value in Haskell
I want to check the condition of the previous if condition
to determine the next if condition
is to be executed or not. 我想检查上一个if condition
以确定下一个if condition
是否要执行。 Each if condition
may return a value. 每个if condition
可以返回一个值。
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 编辑:对不起,我之前提供的示例有点奇怪... :(这是我的真实示例,我想简化go if-then-else
ToMove的if-then-else
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. 编辑:错误的例子当这个东西用Java编写时,我可能会使用可变的布尔标志,并返回可变的数据。
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. 但是在Haskell中, 没有可变数据,只有if-then-else
条件。 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.... 然后代码将看起来像这样,并且我想简化一下,因为在我的实际工作中,共有8个级别的if-then-else
,它们看起来很糟糕且混乱。
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 Java if I wanted to do the following: 在Java中,如果我想执行以下操作:
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. 我实际上所做的是从func1(args)
, func2(args)
, func3(args)
, func4(args)
中找到返回非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. 在Haskell中,我func1
, func2
, func3
和func4
建模为返回Maybe a
值的函数,以便它们在失败时可以不返回Nothing
。
func1, func2, func3, func4 :: Int -> Maybe Result
Then I can use the <|>
operator (from Control.Applicative
), which has the following definition for Maybe a
: 然后,我可以使用<|>
运算符(来自Control.Applicative
),对于Maybe a
具有以下定义:
Nothing <|> x = x
x <|> _ = x
So I can convert the above Java to 所以我可以将上面的Java转换为
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. 并且由于懒惰求值的奇迹,仅当func1 arg
返回Nothing
时才对func2 arg
求值,这与Java示例中相同。
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, 除了漂亮的就业<|>
那风铃草给了和的类似建议sclv ,另一种常见的方法是使用警卫,并利用懒惰,
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. 由于懒惰,仅在需要时才评估move i
( i = 3, 2, 1
3,2,1)。
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. 在给定的情况下, move 3 <|> move 2 <|> move 1
更好,但是在条件需要评估具有不同返回类型的不同函数的情况下,可以在where
子句中使用保护和惰性绑定自然的解决方案,以避免尴尬嵌套if
秒。
edit : Here's some code for the new example: 编辑 :这是新示例的一些代码:
move p routes points w h
| length routes == 2 = routes
| otherwise = find (not . null) . map gtm [tallRightCorner, tallRightBCorner, tallLeftBCorner]
where gtm f = goingToMove (f p) routes points w h
Note that this returns a maybe. 请注意,这可能返回一个。 You can use fromMaybe
to stick in a default case. 您可以使用fromMaybe
坚持默认情况。
Here's the old (but typechecking) code from the first proposed example 这是第一个建议的示例中的旧代码(但类型检查)
move 0 = "Finished the recursion"
move n = concat . maybeToList . msum $ map move' [3,2,1]
where move' x = let mx = move x in if null mx then Nothing else Just mx
You want routes
if its length is 2 or the first non-null result from a series of applications of goingToMove
that vary by which corner function is applied to p
. 您需要routes
如果routes
的长度为2或goingToMove
一系列应用的第一个非空结果, goingToMove
将哪个角函数应用于p
。
move p routes points w h
| length routes == 2 = routes
| otherwise = head
$ filter (not . null)
$ map tryMove corners
where tryMove f = goingToMove (f p) routes points w h
corners = [ tallRightCorner
, tallRightBCorner
, tallLeftBCorner
-- et cetera
]
An option without Maybe could be to add a flag to the recursion (in the example below, you would call the function with the flag set to one): 没有Maybe的选项可能是在递归中添加一个标志(在下面的示例中,您可以将标志设置为一个来调用该函数):
move p routes points wh 1 将p条路线移至wh 1
move p routes points w h flag
| (length routes) == 2 = routes
| otherwise =
if null result then move p routes points w h (flag+1)
else result
where result = case flag of
1 -> goingToMove (tallRightCorner p) routes points w h
2 -> goingToMove (tallRightBCorner p) routes points w h
3 -> goingToMove (tallLeftBCorner p) routes points w h
--...etc.
_ -> []
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.