Haskell在一个条件下定义多个变量?

时间:2013-09-30 19:59:13

标签: haskell if-statement where-clause let

好吧,我可能做错了,但它让我把头发拉了出来。我找不到任何可以做我想做的事情

拿这个伪代码

my_function left right
    = another_function new_left new_right (fourth_function new_left new_right)
        where new_left = if some_condition then left else third_function left
            new_right = if some_condition then third_function right else right

如何避免重新检查some_condition?我不是在讨论将some_condition保存为where构造中的另一个变量。如果我将lets放入if我,然后复制in another_function new_left new_right

在命令式语言中,我可以做类似

的事情
int new_left;
int new_right;
if (condition) {
    new_left = left;
    new_right = third_function(right);
} else {
    new_left = third_function(left);
    new_right = right;
}
return another_function(new_left, new_right, fourth_function(new_left, new_right));

我知道在一个函数式语言中你不应该考虑按顺序做事,而应该把它作为表达式的组合,所以我只是想找一种方法来编写原始的伪代码,这样就干了。这似乎是一个简单而相对常见的案例。

修改

很抱歉这个混乱。我无法内联third_function left/right因为我需要使用它的值两次(更新的伪代码)。 fourth_function无法移动another_function

3 个答案:

答案 0 :(得分:5)

怎么样

my_function left right | somecondition = 
                         another_function left (third_function right)
                       | otherwise     =
                         another_function (third_function left) right

使用新编辑

my_function left right = ...
  where (new_left, new_right) | somecondition = (left, third_function right)
                              | otherwise     = (third_function left, right)

答案 1 :(得分:0)

也许最快捷的方式是

my_function left right
      = uncurry another_function $ if some_condition
                                    then (left, third_function right)
                                    else (third_function left, right)

但是jozefg的建议是相当清洁的IMO。


至于更新的问题:当重新使用结果时,实际上将它们命名为变量通常是好的,jozefg再次展示了如何在你的问题中做到这一点。但是(也是为了你的必要事情):Haskell有monad,它可以用于任何命令(当然还有更多)。在您的情况下,Reader monad,又名函数可以解决问题:

import Control.Monad.Instances

my_function left right = 
        ( uncurry fourth_function >>= flip (uncurry another_function) )
         $ if some_condition
            then (left, third_function right)
            else (third_function left, right)

但这种风格的可读性值得怀疑。

arrows的助手确实有所改善,其中的功能又是一个特例:

import Control.Arrow

my_function = curry $
        ( uncurry fourth_function >>= flip (uncurry another_function) )            
        . (if some_condition then second else first) third_function

答案 2 :(得分:0)

如果只使用简单的函数编程,是的,我们可以使用“if”。

如果我们几乎没有“左”,Monads或Monoids(Maybe aEither a bAny aAll a,......)是合适的。:

foo = do
   if cond1 then Just smths1 else Nothing
   if cond2 then Just smths2 else Nothing
   if cond2 then Just smths2 else Nothing
   if cond2 then Just smths2 else Nothing
   if cond2 then Just smths2 else Nothing

如果我们有很多“左”和“右”,箭头是合适的:

foo = proc (l,r) -> do
    nl <- (if cond1 then idA else arr . foo1)   -< l
    nr <- (if cond2 then arr . foo2 else idA )  -< r
    ...