2013-09-10 2 views
3

Я писал Haskell сегодня днем, и у меня есть список условий, которые должны быть удовлетворены. Если все они истинны, я хочу вернуть true, если один из них false, а затем возвращает false.Haskell: Проверьте, соблюдены ли все условия. Если они вернутся в противном случае false

У меня есть метод, который работает, но мне просто интересно, есть ли лучший способ реализовать его для удобочитаемости/эффективности.

Вот что у меня есть:

checkMatch :: Person -> Person -> Bool 
checkMatch seeker candidate 
    | gender candidate == preferedGender seeker 
    && gender seeker == preferedGender candidate 
    && minAcceptableAge seeker <= age candidate 
    && maxAcceptableAge seeker >= age candidate 
    && minAcceptableAge candidate <= age seeker 
    && maxAcceptableAge candidate >= age seeker = True 
    | otherwise = False 

Пол определяется как:

data Gender = Male | Female (Eq) 

Так что я просто выравнивали & & 'S и |' s, чтобы сделать это выглядеть немного лучше, но Я чувствую, что должен быть лучший способ, но, похоже, не может найти ничего, что бы искало Google.

Спасибо, продвинутый!

+0

BTW, [это _preferred _] (HTTP : //en.wiktionary.org/wiki/prefered). – leftaroundabout

ответ

7

Вы можете потерять охранников и использовать and, чтобы проверить условия:

checkMatch :: Person -> Person -> Bool 
checkMatch seeker candidate = and [ 
    gender candidate   == preferedGender seeker 
    , gender seeker    == preferedGender candidate 
    , minAcceptableAge seeker <= age candidate 
    , maxAcceptableAge seeker >= age candidate 
    , minAcceptableAge candidate <= age seeker 
    , maxAcceptableAge candidate >= age seeker 
    ] 
+0

Удивительно, я подумал, что могу использовать все, но не знал об id. Благодаря! :) – visi0n

+2

Вам не нужно 'id'. Используйте 'и :: [Bool] -> Bool', это также в прелюдии. – leftaroundabout

+0

@ visi0n Вы также можете использовать 'all (== True)', но 'all id' делает то же самое. – jtobin

1

Ну, во-первых, вы можете and сторожевые условия просто с ,.

Далее, я должен реорганизовать minAccAge <= age && maxAccAge >= age скороговоркой в ​​специальную функцию, скажем,

acceptsAge :: Person -> Age -> Bool 
judge `acceptsAge` age 
    = age >= minAcceptableAge judge && age <= maxAcceptableAge judge 

Осталось

checkMatch :: Person -> Person -> Bool 
checkMatch seeker candidate 
    | gender candidate == preferedGender seeker 
    , gender seeker == preferedGender candidate 
    , seeker `acceptsAge` age candidate 
    , candidate `acceptsAge` age seeker   = True 

Я бы оставить его в этом то, что два preferedGender проверки не может значительно сократятся.

+0

Я думаю, что предпочитаю использовать '' 'и''' вместо охранников, но мне нравится функция acceptsAge. Я положил это в блок '' 'где'''. Благодаря! – visi0n

1

Что вы спрашиваете, это вопрос стиля, поэтому нет правильного или неправильного ответа. Однако, вот несколько предложений.

Во-первых, вы пишете эквивалент этой модели:

isTrue value | value == True = True 
      | otherwise  = False 

Что, конечно, может быть упрощена:

isTrue value = value 

Во-вторых, как вы проверяете несколько тестов, которые все необходимость в Верно, вы можете использовать функцию and и передать свои тесты в качестве элементов списка. Это приведет к возврату True, если все элементы True, в противном случае это будет короткое замыкание и возврат False.

Подставив эти две идеи вместе мы получаем:

checkMatch :: Person -> Person -> Bool 
checkMatch seeker candidate 
    = and [gender candidate == preferedGender seeker, 
     gender seeker == preferedGender candidate, 
     minAcceptableAge seeker <= age candidate, 
     maxAcceptableAge seeker >= age candidate, 
     minAcceptableAge candidate <= age seeker, 
     maxAcceptableAge candidate >= age seeker] 

... который, вероятно, как я хотел бы написать.

2

Вы могли бы злоупотреблять, может быть монады синтаксического сахара как:

a |==| b = guard $ a == b 
a |>=| b = guard $ a >= b 
a |<=| b = guard $ a <= b 
a |/=| b = guard $ a /= b 

checkMatch :: Person -> Person -> Bool 
checkMatch seeker candidate = Just() == do 
    gender candidate |==| preferedGender seeker 
    gender seeker |==| preferedGender candidate 
    minAcceptableAge seeker |<=| age candidate 
    maxAcceptableAge seeker |>=| age candidate 
    minAcceptableAge candidate |<=| age seeker 
    maxAcceptableAge candidate |>=| age seeker 
+0

довольно милое решение, которое вы получили там –

+0

@ JustinL. да, мое воображение убежало от меня. –

+1

вам, возможно, удастся избежать использования какого-либо 'assert' DSL –

1

Я заметил, что ваш код содержит некоторое дублирование, потому что вы проверить Eveything в обоих направлениях. Я хотел бы определить вспомогательную функцию checkAcceptable, что только одно направление и чем называть эту функцию дважды:

checkAcceptable :: Person -> Person -> Bool 
checkAcceptable seeker candidate = 
    gender candidate == preferedGender seeker && 
    minAcceptableAge seeker <= age candidate && 
    maxAccetableAge seeker >= age candidate 

checkMatch :: Person -> Person -> Bool 
checkMatch seeker candidate = 
    checkAcceptable seeker candidate && 
    checkAcceptable candidate seeker 
1

Для минимизации кода, вы можете написать его как этот

inRange x (a,b) = a <= x && x <= b 

checkOneWay a b = gender b == preferredGender a 
       && age b `inRange` (minAcceptableAge a, maxAcceptableAge a) 

checkMatch candidate seeker = checkOneWay candidate seeker 
          && checkOneWay seeker candidate 

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

  • Нет связанных вопросов^_^