如何简化嵌套 - 如果使用在Haskell中返回值

时间:2013-02-06 18:20:08

标签: haskell if-statement recursion functional-programming tail-recursion

我想检查上一个if condition的条件,以确定是否要执行下一个if condition。每个if condition都可以返回一个值。

编辑:对不起,我之前提供的示例看起来有点奇怪...... :( 这是我的真实示例,我想简化{strong> goToMove 的<{1}}

if-then-else

编辑:错误的例子 当这个东西用java编写时,我可能会使用一个可变的布尔标志,并返回一个可变数据。

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 

但是在Haskell中,没有可变数据,只有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; } } 条件。然后代码看起来像这样,我想简化这个,因为在我的实际工作中,那里是if-then-else的8级,看起来很糟糕...... [/ p>

if-then-else

4 个答案:

答案 0 :(得分:16)

在Java中如果我想要执行以下操作:

result = func1(arg);
if (result == null){
  result = func2(arg);
  if (result == null){
    result = func3(arg);
    if (result == null){
      result = func4(arg);
    }
  }
}
return result;

我实际上在做的是从func1(args)func2(args)func3(args)func4(args)中找到返回非空的第一个结果。

在Haskell中,我将func1func2func3func4建模为返回Maybe a值的函数,以便它们可以如果失败则返回Nothing

func1, func2, func3, func4 :: Int -> Maybe Result

然后我可以使用<|>运算符(来自Control.Applicative),该运算符具有Maybe a的以下定义:

Nothing <|> x = x
x       <|> _ = x

所以我可以将上面的Java转换为

func1 arg <|> func2 arg <|> func3 arg <|> func4 arg

由于懒惰评估的奇迹,func2 arg仅在func1 arg返回Nothing时进行评估,与Java示例相同。

答案 1 :(得分:1)

编辑:以下是新示例的一些代码:

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

请注意,这会返回一个可能。您可以使用fromMaybe来保留默认情况。

这是第一个提出的示例中的旧(但是类型检查)代码

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

答案 2 :(得分:1)

如果routes的长度为2,或者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 ]

{{1}}

答案 3 :(得分:0)

没有Maybe的选项可能是为递归添加一个标志(在下面的示例中,您将调用函数并将标志设置为1):

移动p路线点数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.
                        _ -> []