2

Alright, I'm probably doing this wrong but it has got me pulling my hair out. I haven't been able to find anything to do what I want

Take this pseudocode

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

How can I avoid rechecking some_condition? And I'm not talking about saving some_condition as another variable in the where construct. If I put lets inside the if I then duplicate the in another_function new_left new_right.

In an imperative language I could do something like

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));

I know in a functional language you're not supposed to think of doing things in a sequence, but rather as a composition of expressions, so I'm just looking for a way to write the original pseudocode such that it's DRY. And it seems like a simple and relatively common case.

Edit

Sorry for the confusion. I can't inline third_function left/right because I need to use it's value twice (updated pseudocode). And fourth_function can't be moved inside another_function

4

3 回答 3

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)
于 2013-09-30T20:04:45.610 回答
0

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

如果我们有很少的“left”,则 Monad 或 Monoids ( Maybe a, Either a b, Any a, All 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
    ...
于 2013-09-30T22:16:33.153 回答
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,它可以用于任何命令(当然还有更多)。在您的情况下,Readermonad,又名函数可以解决问题:

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
于 2013-09-30T20:04:33.220 回答