5
\$\begingroup\$

I've been learning Haskell from LYAH for quite some time, and as a first practice for Chapter 7: Modules, I decided to make a simple numTimesFound function: it returns the number of times an element is found in a list.

Here's my working code:

numTimesFound :: Ord a => a -> [a] -> Integer
numTimesFound _ [] = 0
numTimesFound x list
 | x `notElem` list = 0
 | otherwise =
 let
 appearencesTable = map (\full@(first:_) -> (first, length full + 1)) . group . sort $ list
 appearencesOfX = snd $ head $ filter (\(elem, _) -> elem == x) appearencesTable
 in
 toInteger appearencesOfX

Personally, I think I take the cake for using Haskell features, but I also think that the intent of this code is hard to understand. One of my major gripes with it is that it's hard to tell what the appearencesTable actually is from the code - it's a list of tuples that gives you the number of times each element was found. For example, for the list [1, 1, 1, 2, 2, 3, 3, 3, 3, 4, 4, 5] the appearencesTable is [(1, 3), (2, 2), (3, 4), (4, 2), (5, 1)]. If you know that it's pretty easy to get what the rest of the code is trying to do, but it still does require quite a bit of study for such a trivial function.

I would greatly appreciate any help in improving the readability of this code.

200_success
145k22 gold badges190 silver badges478 bronze badges
asked Aug 25, 2016 at 6:28
\$\endgroup\$
1

1 Answer 1

8
\$\begingroup\$

Since your type a is required to be an Ord you can access Eq functions. This makes counting occurrences a bit simpler, because you can just filter and count the matching elements:

numTimesFound :: Ord a => a -> [a] -> Integer
numTimesFound _ [] = 0
numTimesFound x list = sum $ map (\a -> 1) $ filter (== x) list

Of course we don't need to stop there. We can use function composition and length to write the last line as:

numTimesFound x xs = (length . filter (== x)) xs

In addition to that 200_success raises an interesting point in the comments:

Actually, there is no reason to require Ord a, when Eq a will do

answered Aug 25, 2016 at 7:18
\$\endgroup\$
5
  • \$\begingroup\$ Man that was simpler than I thought! I guess the style of thinking has to be pretty different to write readable code in Haskell. Thanks so much! \$\endgroup\$ Commented Aug 25, 2016 at 7:28
  • \$\begingroup\$ Note that you don’t need the explicit case to handle the empty list at all; count will happily return 0 if the list is empty. \$\endgroup\$ Commented Aug 25, 2016 at 7:43
  • 1
    \$\begingroup\$ Wait, I just realized - the count function is the same as length, so I can just write my original function as numTimesFound x = length . filter (==x)! I am so dumb! \$\endgroup\$ Commented Aug 25, 2016 at 7:44
  • 4
    \$\begingroup\$ Actually, there is no reason to require Ord a, when Eq a will do. \$\endgroup\$ Commented Aug 25, 2016 at 8:55
  • \$\begingroup\$ @200_success: Yes, that is true. The only reason I was using Ord originally was because I used sort. \$\endgroup\$ Commented Aug 25, 2016 at 13:56

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.