3

今天下午我正在写一些 Haskell,我列出了必须满足的条件。如果它们都为真,我想返回真,如果其中一个为假,则返回假。

我有一个有效的方法,但我只是想知道是否有更好的方法来实现它以提高可读性/效率。

这是我所拥有的:

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 让这看起来更好一点,但我觉得必须有更好的方法,但似乎无法想出任何搜索谷歌的东西。

先谢谢了!

4

6 回答 6

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
  ]
于 2013-09-10T22:35:57.860 回答
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
于 2013-09-10T22:51:56.120 回答
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]

...这可能就是我会写它的方式。

于 2013-09-10T22:43:06.967 回答
1

我注意到您的代码包含一些重复,因为您在两个方向上都检查了一切。我会定义一个辅助函数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
于 2013-09-10T23:53:35.533 回答
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
于 2013-09-11T08:24:26.870 回答
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检查不能减少太多。

于 2013-09-10T22:42:43.047 回答