0
votes

I've been trying to define a function which, given a list of Integers and an Integer n, returns a Boolean indicating whether n occurs exactly once in the list.

I have this, but it is not working and I cannot figure it out

once :: [a] -> (a -> Bool) -> Bool 
filter _ [] = []  
filter p (x:xs)   
    | p x       = x : filter p xs  
    | otherwise = filter p xs 

An example of what I want would be:
Main>  once [2,3,2,4] 2
False
Main> once [1..100] 2
True
4

4 Answers

6
votes

As I thought my former solution was ugly, I asked in another forum and got this as answer:

once :: Eq a => a -> [a] -> Bool
once x = (== [x]) . filter (== x)

I think you can't write that function much nicer, and in contrast to the accepted answer it's lazy.

2
votes
once :: (Eq a) => [a] -> a -> Bool
once xs x = (== 1) $ length $ filter (== x) xs
2
votes

Well, you can filter the list, then see how many elements are in the resulting filter, right?

To get you started:

 > filter (== 2) [1,2,3,4,5]
 [2]

 > filter (== 2) [1,2,3,4,5,2,2]
 [2,2,2]

And to fold your list down to a Bool value, here, an example where we test if a list has three elements, returning a Bool:

 > isThree (a:b:c:[]) = True
 > isThree _          = False 

So it is just a short matter of composing such functions:

 > isThree . filter (==2)

or your variant (e.g. matching for lists of length 1).

0
votes

Here is another version:

once x = not . (\xs -> null xs || x `elem` tail xs) . dropWhile (/= x)

--lambda hater version
import Control.Applicative
once x = not . ((||) <$> null <*> (elem x).tail) . dropWhile (/= x)

Of course it can't deal with infinite lists that contain zero or one x, but at least it terminates in case of more than one occurrence of x.