2014-11-19 3 views
2

Как избежать повторяющихся х в этой команде HaskellКак я могу избежать вызова повторяющихся функций в Haskell

ccheck :: Balance -> Integer 
ccheck b  | x >= 1200 = x - 7 
      | otherwise = x 
       where x = account b 
+3

На самом деле это не кажется повторяющимся. –

+0

есть ли способ избежать х и закончить все это с помощью одного x. Может быть в одной или двух строках – Myke

+0

Возможно, нет. Я не знаю Haskell, что хорошо, но что-то вроде 'x - (x> = 1200? 7: 0)' может привести вас к двум. В любом случае, это не стоит жертвовать читабельностью. –

ответ

6

Ну что ж, вы можете сделать практически что угодно без точек.

import Control.Arrow 
ccheck = uncurry (+) . (min 0 . (*7) . signum . (1199-) &&& id) . account 

но WTH. Ваша версия в порядке, гораздо яснее, что происходит, и, как заметил полковник Тридцать два, это не так много.

2

Вы можете полностью опустить его, если вы хотите:

ccheck = ((+) <*> ((-7) *) . signum . (1+) . signum . (-1200 +)) . account 

Однако, это не более читаемый, чем условный случай (в частности, чтобы избежать оператора if, мы используем signum . (1+) . signum, который является немного головоломкой, самый правый отображает целое число до набора {-1, 0, 1} и (1+) преобразует это в {0, 1, 2}, что следующие s ignum снова уменьшается до {0, 1}.

2

Вы можете сделать это намного менее читаемым, как

ccheck = join (liftM2 if' (>= 1200) (subtract 7)) . account 
    where if' b l r = if b then l else r 
+0

'if '(> = 1200) (subtract 7)' на самом деле выглядит довольно хорошо. Мы могли бы написать все это как «if» (> = 1200) (вычесть 7). где if 'pmx = if px, тогда mx else x', и это было бы неплохо ... но это снова будет содержать 'x' duplication ... – leftaroundabout

+1

@leftaroundabout Я честно просто пошёл с предложением' pointfree', но Я признаю, что было бы полезно иметь функции 'when' и' except', определенные как 'когда pfx = if px, тогда fx else x' и' если p = when (not. P) ', переименование функций из' Control .Monad' должен быть суффикс с 'M', тогда мы могли бы написать код типа' ccheck = when (> = 1200) (вычесть 7). account' или 'ccheck = if (<1200) (вычесть 7). account'. Он просто лучше меня читает. – bheklilr

2

"Улучшение" ответ от @bheklilr:

import Control.Monad 
import Data.Bool 
ccheck = liftM3 bool id (subtract 7) (>= 1200) . account 

Еще один пример "бессмысленного" стиля.

1

Я не думаю, что код повторяется, но вот мой прием все же. Во-первых, ввести следующие комбинатор:

cond p f g x = if p x then f x else g x 

Затем определяют ccheck как:

ccheck = cond (>= 1200) (subtract 7) id . account 
0

Из верхней части моей головы, если вы хотите сделать больше проверок:

ccheck = chainConditions [((>=1200), subtract 7] id . account 

chainConditions :: [(a -> Bool, a -> b)] -> (a -> b) -> a -> b 
chainConditions [] g x = g x 
chainConditions ((p,f):rest) g x = 
    | p x = f x 
    | otherwise = chainConditions rest g x 

Это вероятно, также выражается как foldr (.) otherwiseFunction (map (uncurry cond) conditions), используя ответ @Xavier Pinho, но это дикая догадка! Вы можете слишком сильно затухать ;-)

Смежные вопросы