仅返回3个列表中的1个函数的True

时间:2013-03-26 18:48:52

标签: function haskell functional-programming

因为我很确定在Haskell中使用全局变量是不受欢迎的。我想知道无论如何我可以实现以下目标吗?

-- 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]

无论如何,我可以确保只有其中一个返回真实吗?

  

例如,[1,2,3,5],我只想要listHasOdd返回   真,这是[真,假,假]。 (从上到下评估)。

     

另一个例子,[2,4,6,8,10,12,14],返回值应为[False,True,False]。

     

换句话说,checkList [1,2,3,5]返回[True,False,False],checkList [2,4,6,8,10,12,14]返回[False,True,False]

     

**在我的例子中,最后一个函数总是为False,因为它无法访问。

我知道我可以做一个if语句来检查前一个是True但是这看起来很愚蠢。或者这实际上是这样做的方式? (考虑到Haskell“记得”前一个函数的结果)

2 个答案:

答案 0 :(得分:3)

我没有看到它的意义,但

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

会产生所需的结果,它只会评估函数,直到其中一个函数返回True(或者到达函数列表的末尾)。

答案 1 :(得分:2)

这是我能想到的最好的。例如,它通过相对无痛的方式来处理扑克手的可能结果的数量。

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

但即使这是愚蠢的:为什么不直接使用[Bool]而不是生成Outcome


编辑或者我们可以关注的含义

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`)