2013-09-10 62 views
3

今天下午我正在寫一些Haskell,我有一個必須滿足的條件列表。如果它們都是真的,我想返回true,如果其中一個是false,則返回false。Haskell:檢查是否所有條件都是真的。如果它們返回true否則爲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) 

所以我只是對準& &的和|的,使這個看起來好一點,但我覺得必須有更好的方式,但似乎無法提出任何搜索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',它也在Prelude中。 – 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

我想我更喜歡使用'''和'''而不是守衛,但我喜歡acceptAge功能。我把它放在''''哪裏''塊。謝謝! – 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 
相關問題