rlhh
rlhh

Reputation: 903

Returning True for only 1 Function out of the list of 3

Since I'm pretty sure that using global variables in Haskell is frowned upon. I'm wondering is there anyway I can achieve the following?

-- list has elements that are odd
listHasOdd :: [Integer] -> Bool
-- list has elements that are even
listHasEven :: [Integer] -> Bool
--list has a length > 5
longList :: [Integer] -> Bool

-- Maps the function to a [Bool]
-- This function cannot be modified to fix the problem.
checkList :: [Integer] -> [Bool]
checkList xs = map (\ y -> y xs) listChecker
where listChecker = [listHasOdd, listHasEven, longList]

Is there anyway that I can ensure that only one of them returns true?

For example, [1,2,3,5], I would want only want listHasOdd to return True which is [True, False, False]. (Evaluated from top to bottom).

Another example, [2,4,6,8,10,12,14], the returns should be [False, True, False].

In other words, checkList [1,2,3,5] returns [True, False, False], checkList[2,4,6,8,10,12,14] returns [False, True, False]

**The last function would always be False in my example, since it is unreachable.

I know I can do an if statement to check if the previous one is True but that seems like a pretty dumb idea. Or is that actually the way to do it? (Considering Haskell "remembers" the results of the previous function)

Upvotes: 0

Views: 468

Answers (2)

dave4420
dave4420

Reputation: 47052

This is the best I can come up with. It generalises relatively painlessly to handle the number of possible outcomes of a poker hand, for example.

data Outcome
    = ListHasOdd
    | ListHasEven
    | LongList
    | Nope
  deriving Eq

outcomeFromList :: [Integer] -> Outcome
outcomeFromList xs
    | any odd xs    = ListHasOdd
    | any even xs   = ListHasEven
    | 5 < length xs = LongList
    | otherwise     = Nope

listHasOdd = (ListHasOdd ==) . outcomeFromList
listHasEven = (ListHasEven ==) . outcomeFromList
longList = (LongList ==) . outcomeFromList

But even this is stupid: instead of generating a [Bool], why not just use the Outcome directly?


Edit: Or we could pay attention to what the functions mean.

listHasOdd xs = any odd xs

listHasEven [] = False
listHasEven xs = all even xs
-- if not all of them are even, then at least one must be odd,
-- and `listHasOdd` would give `True`

longList _ = False
-- if the list has at least 5 elements,
-- then either the list has at least one odd element
-- (and `listHasOdd` would give `True`)
-- or the list has at least five even elements
-- (and `listHasEven` would give `True`)

Upvotes: 2

Daniel Fischer
Daniel Fischer

Reputation: 183888

I don't see the point of it, but

foldr foo [] $ map ($ xs) [listHasOdd, listHasEven, longList]
  where
    foo True zs = True : map (const False) zs
    foo False zs = False : zs

would produce the desired result, and it would only evaluate the functions until one of them returned True (or the end of the list of functions is reached).

Upvotes: 3

Related Questions