Reputation: 903
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
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
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