我想检查列表中的布尔元素是全是True,全是False还是True和False.这是我现在的代码:
data Answer3 = Just_True | Just_False | Both deriving (Eq, Ord, Show)
type A3 = Answer3
checkBoolean :: [Bool] -> A3
checkBoolean (x:x1:xs) = if (length (x:x1:xs) `mod` 2) == 0
then if (x && x1) && checkBoolean'(x1:xs)== True
then Just_True
else if (x && x1) == True
then Both
else if checkBoolean'(xs)== True
then Both
else Just_False
else if x && checkBoolean'(x1:xs) == True
then Just_True
else if x == False
then Just_False
else Both
checkBoolean':: [Bool] -> Bool
checkBoolean' (x:xs) = x && (checkBoolean'(xs))
checkBoolean' [] = True
Run Code Online (Sandbox Code Playgroud)
调用
*Main> checkBoolean [False, False, False]
Just_False
Run Code Online (Sandbox Code Playgroud)
要么
*Main> checkBoolean [True, True, True]
Just_True
Run Code Online (Sandbox Code Playgroud)
要么
*Main> checkBoolean [True, False, False]
Both
Run Code Online (Sandbox Code Playgroud)
给出正确的结果.但
*Main> checkBoolean [False, False, True, False, True]
Just_False
Run Code Online (Sandbox Code Playgroud)
和
*Main> checkBoolean [False, False, True]
Just_False
Run Code Online (Sandbox Code Playgroud)
不按我的意图工作.[False, False, True, False, True]既是, [False, False, True]也是两者
我知道我没有想到所有可能的情况,这就是为什么这不起作用,但有没有一种有效的方法来写这个而不用写这么多if else语句?
Die*_*Epp 10
功能all或any浮现在脑海中的第一:
any :: Foldable t => (a -> Bool) -> t a -> Bool
all :: Foldable t => (a -> Bool) -> t a -> Bool
Run Code Online (Sandbox Code Playgroud)
如果我们专注于列表,我们将替换t为[],这使得它看起来像:
any :: (a -> Bool) -> [a] -> Bool
all :: (a -> Bool) -> [a] -> Bool
Run Code Online (Sandbox Code Playgroud)
我们可以将所有元素与第一个元素进行比较,以查看列表是否包含所有相同的值.如果任何元素不同,那么我们知道列表是混合的.
checkBoolean (x:xs)
-- Check if any elements are not equal to the first one.
| any (/= x) xs = Both
| x = Just_True
| otherwise = Just_False
Run Code Online (Sandbox Code Playgroud)
我们可能也希望处理退化情况:
-- "Just_True" is arbitrary... you could say "Just_False", too.
checkBoolean [] = Just_True
Run Code Online (Sandbox Code Playgroud)
值得注意的是,作为一个练习,你发现以递归方式编写函数是有价值的,而不使用像allor 这样的高阶函数any,即使它们在前奏中.这是一个替代的尾递归实现:
checkBoolean [] = Just_True
checkBoolean (x:xs) = check xs
where
check [] = if x
then Just_True
else Just_False
check (y:ys) = if x == y
then check ys
else Both
Run Code Online (Sandbox Code Playgroud)
我不希望在实际的项目代码中看到这个更长的版本.
哦,哇,你有点过分复杂了.
有一个非常有用的函数叫做all:
all :: (a -> Bool) -> [a] -> Bool
Run Code Online (Sandbox Code Playgroud)
它检查谓词的所有元素,对于布尔值可能只是一对id和not函数,但是你也可以显式检查一个值的相等性,这使代码非常易读:
checkBoolean xs =
if all (== True) xs then Just_True
else if all (== False) xs then Just_False
else Both
Run Code Online (Sandbox Code Playgroud)
关于空list([])的情况可能更明确一些也是一个好主意.它应该是Just_True,Just_False,Both干脆,或者另一个值?
你错过了处理空列表的案例:
-- checkBoolean [] = Neither
data Answer4 = Just_True | Just_False | Both | Neither
Run Code Online (Sandbox Code Playgroud)
Answer4有一个简单的,如果啰嗦的Semigroup实例.
instance Semigroup Answer4 where
-- like combines with like
Just_True <> Just_True = Just_True
Just_False <> Just_False = Just_False
-- Neither is "like" anything
x <> Neither = x
Neither <> x = x
-- otherwise, you get Both
_ <> _ = Both
Run Code Online (Sandbox Code Playgroud)
还有一个简单的Monoid例子:
instance Monoid Answer4 where
mempty = Neither
Run Code Online (Sandbox Code Playgroud)
现在,如果你有办法将a转换Bool为Answer4
lift :: Bool -> Answer4
lift True = Just_True
lift False = Just_False
Run Code Online (Sandbox Code Playgroud)
您可以快速将列表减少Bool到单个Answer4值:
-- foldMap :: (Foldable t, Monoid m) => (a -> m) -> t a -> m
-- Here, t ~ [], a ~= Bool, and m ~ Answer4, for a specialized type
-- foldMap :: (Bool -> Answer4) -> [Bool] -> Answer4
checkBoolean :: [Bool] -> Answer4
checkBoolean = foldMap lift
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1121 次 |
| 最近记录: |