简体   繁体   中英

How do you detect if a list has exactly 3 items in Haskell?

I have this but I got an error:

-- test if a list contains exactly three characters
test :: [Char] -> Bool
test xs   | [_ , _ , _] = True
          | otherwise = False

Pattern matching happens on the left side of the vertical bar. Thus:

test :: [Char] -> Bool
test [_, _, _] = True
test _         = False

As Norman Ramsey rightly notes below, the following code is not a robust alternative solution (because it is very inefficient when applied to (long) finite lists and does not halt on infinite lists) and should thus not be used:

test :: [Char] -> Bool
test xs = length xs == 3

Moreover, length xs == 0 should always be replaced with null xs .

Edit: the question which naturally arises is: how do we generalize this? What if we want to test whether a list has exactly n elements? What if the input may be infinite? Here's a solution where the cost is either n or the length of the list, whichever is smaller—and that's as efficient a solution, asymptotically, as we can possibly hope for:

hasLength :: Int -> [a] -> Bool
hasLength n []     = n == 0
hasLength 0 (x:xs) = False
hasLength n (x:xs) = hasLength (n-1) xs

Usage:

*Main> hasLength 3 [1..2]
False
*Main> hasLength 3 [1..3]
True
*Main> hasLength 3 [1..4]
False
*Main> hasLength 3 [1..] 
False

It is unsafe to call this function with a negative length; if the list is infinite, the function won't terminate, and if the list is finite, it will return False with cost proportional to the length of the list. An easy fix would be to check in advance (on the first call only) that n is nonnegative, but this fix would ugly up the code.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM