0

I wrote a function count :: Char -> String -> Int that counts the number of occurrences of a Char inside a String. Code sample:

module Main where

import Data.List

main :: IO ()
main = do
        print $ count 'a' "abcaaba"

count :: Char -> String -> Int
count = length . elemIndices

The compile error I get is

* Couldn't match type `Int' with `String -> Int'
  Expected type: Char -> String -> Int
    Actual type: Char -> Int
* Possible cause: `(.)' is applied to too many arguments
  In the expression: length . elemIndices
  In an equation for `count': count = length . elemIndices

OK, I could write count x y = length $ elemIndices x y which works. But I argue we have

(1) (.) :: (b -> c) -> (a -> b) -> a -> c

(2) elemIndices :: Eq a => a -> [a] -> [Int] and

(3) length :: [a] -> Int

If count shall be a composition of (2) and (3) then in (1) we need obviously a = Char -> [Char] and c = Int. And if b = [Int] we get

(1') (.) :: ([Int] -> Int) -> (Char -> [Char] -> [Int]) -> Char -> [Char] -> Int

which means I can compose (2) and (3) to get Char -> [Char] -> Int.

Questions:

  1. Why is the composition I wrote failing to compile?
  2. Where is my reasoning going wrong?
TobiMcNamobi
  • 4,687
  • 3
  • 33
  • 52
  • 1
    In many Haskell books and tutorials some of the basics of Haskell mentioned in between the lines sometimes get skipped or overlooked. [This](https://www.fpcomplete.com/blog/2012/09/ten-things-you-should-know-about-haskell-syntax) article is a great one to have a look at. – Redu May 01 '17 at 14:46

1 Answers1

5

-> in types is right associative:

elemIndices :: Eq a => a -> [a] -> [Int]

means

elemIndices :: Eq a => a -> ([a] -> [Int])

When you use elemIndices on the right-hand side of (.) :: (b -> c) -> (a' -> b) -> a' -> c, you have

  • a' = a
  • b = [a] -> [Int]

And this is where things break down, because length does not take [a] -> [Int] (a function) as input; it wants a list.


What you can do instead is:

count x y = length (elemIndices x y)

This is the same as (by the definition of (.)):

count x y = (length . elemIndices x) y

Eta reduction:

count x = length . elemIndices x

You should probably stop here because this is where things get a bit crazy.


Prefix notation:

count x = (.) length (elemIndices x)

Definition of (.):

count x = ((.) length . elemIndices) x

Eta reduction:

count = (.) length . elemIndices

Or using an operator section:

count = (length .) . elemIndices

But wait, there's more!

Prefix notation:

count = (.) ((.) length) elemIndices

Definition of (.):

count = (((.) . (.)) length) elemIndices

Removing redundant parens:

count = ((.) . (.)) length elemIndices

Prefix notation:

count = (.) (.) (.) length elemIndices

MAXIMUM BEAUTY ACHIEVED.

melpomene
  • 84,125
  • 8
  • 85
  • 148