我今天下午写了一些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)
所以我只是调整了&amp;&amp;和s'以使它看起来更好一点,但我觉得必须有更好的方法,但似乎无法想出任何搜索谷歌的东西。< / p>
先谢谢!
答案 0 :(得分: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
]
答案 1 :(得分:2)
你可以滥用may monad的语法糖作为:
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
答案 2 :(得分: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
检查不能减少太多。
答案 3 :(得分:1)
你问的是风格问题,所以没有正确或错误的答案。但是,这里有一些建议。
首先,您正在编写此模式的等效内容:
isTrue value | value == True = True
| otherwise = False
当然可以简化为:
isTrue value = value
其次,当您检查 all 所需的多个测试时,您可以使用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]
......这可能就是我写它的方式。
答案 4 :(得分: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
答案 5 :(得分: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