2013-09-30 1 views
1

Хорошо, я, наверное, делаю это неправильно, но это заставило меня вытащить мои волосы. Я не смог найти ничего, чтобы сделать то, что я хочуHaskell определяет несколько переменных при одном условии?

Возьмите этот псевдокод

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

+0

Почему downvote? Неужели ему не хватает исследований, непонятно, что я прошу, упрямый, широкий, вне темы или что-то в этом роде? – Raekye

ответ

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) 
+0

См. Обновленный пост, извините, оставил важную информацию – Raekye

+0

@Raekye обновлен – jozefg

+0

А блестящий. Именно то, что я хотел – Raekye

0

Возможно, самый быстрый способом будет

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

Но jozefg-й внушением, а уборщик ИМО.


Что касается обновленного вопроса: при повторном использовании результатов обычно, хорошо на самом деле сделать их имена переменных, снова jozefg показал, как сделать это в вашей проблеме. Но (также мостик вашему императивному делу): у Хаскелла есть монады, которые можно использовать для чего-либо императивного (и, конечно же, гораздо большего). В вашем случае Reader монады, иначе функция делает трюк:

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 
+0

См. Обновленный пост, извините, оставил важную информацию – Raekye

0

Если просто использовать простое программирование функций, да, мы могли бы использовать «if».

Если у нас есть несколько «левых» с, Монада или Моноиды (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 
    ...