检查列表中的所有bolean元素在Haskell中是否相同

che*_*ire 9 haskell

我想检查列表中的布尔元素是全是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

功能allany浮现在脑海中的第一:

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)

我不希望在实际的项目代码中看到这个更长的版本.


Bar*_*icz 9

哦,哇,你有点过分复杂了.

有一个非常有用的函数叫做all:

all :: (a -> Bool) -> [a] -> Bool
Run Code Online (Sandbox Code Playgroud)

它检查谓词的所有元素,对于布尔值可能只是一对idnot函数,但是你也可以显式检查一个值的相等性,这使代码非常易读:

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干脆,或者另一个值?

  • 很简单,但在这种教育活动中,他应该尝试一次遍历. (2认同)
  • 值得讨论使用`(== True)`和`(== False)`.虽然它们是正确的,但它们并不常见,而且可能更期望或更常见的是看到`id`和`not`. (2认同)

che*_*ner 6

你错过了处理空列表的案例:

-- 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转换BoolAnswer4

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)

  • 我不喜欢这个,因为它不是尾递归。`&lt;&gt;` 操作将堆叠起来。 (2认同)