-1

What does . (dot) stand for? For example it is used in sumDigits but I don't understand what it does.

toDigits m = loop m [] where
    loop x y | x <= 0    = y
             | otherwise = loop (x `div` 10) ((x `mod` 10) : y)

sumDigits = sum . map (sum . toDigits)
Micha Wiedenmann
  • 19,979
  • 21
  • 92
  • 137
  • 2
    on StackOverflow, question edits must not invalidate the answers. – Will Ness Feb 01 '22 at 20:33
  • @MichaWiedenmann I don't understand this either. it's not like Haskell has a _proper_ [clickable documentation](http://www.lispworks.com/documentation/lw50/CLHS/Front/X_Mast_9.htm) or something, which the OP could've easily explored. (one can even search for "dot" on that page... oh my) – Will Ness Feb 03 '22 at 16:53

3 Answers3

7

The . stands for function composition in Haskell.

It allows you to chain different functions. In your case, instead of doing a new function that calls toDigits and then sum over the result, you can use function composition.

sumDigits = sum (map myFunction)

myFunction xs = sum (toDigits xs)

The definition of . is the following.

(.) :: (b -> c) -> (a -> b) -> a -> c  
f . g = \x -> f (g x) 

There's a really good example on stackoverflow already you can check.

Say you have these functions:

even :: Int -> Bool
not :: Bool -> Bool

and you want to define your own myOdd :: Int -> Bool function using the two above.

The obvious way to do this is the following:

myOdd :: Int -> Bool myOdd x = not (even x)

But this can be done more succinctly using function composition:

myOdd :: Int -> Bool myOdd = not . even

The myOdd functions behave exactly the same, but the second one is created by "glue-ing" two functions together.

Ulysse BN
  • 10,116
  • 7
  • 54
  • 82
  • thankyou! Could you please explain me this function ? I want to know what it is doing with 1:2:. Thanks! doubleEveryOther = reverse . zipWith (*) value . reverse where value = 1 : 2 : value – asworeya shrestha Feb 01 '22 at 19:56
  • 1
    `value = 1 : 2 : value` makes the infinite list `[1, 2, 1, 2, 1, 2, ...]`. `doubleEveryOther` grabs a list, reverses it, then pairs every item in the two lists and multiplies them together, then reverses the list again to return it. – Francisco Aguirre Feb 01 '22 at 20:21
  • 1
    You can think of the order of operations as the inverse of the order of compositions, the last `reverse` is called first, then the `zipWith` in the middle, then the first `reverse`. – Francisco Aguirre Feb 01 '22 at 20:23
4

The dot (.) is an infix operator. It is defined so that

(f . g) x = f (g x)

Thus,

sumDigits     =   sum . map (sum . toDigits)
= {- by "eta-expansion" -}
sumDigits xs  =  (sum . map (sum . toDigits))    xs
              = {- by definition of (.) -}
                 sum ( map (sum . toDigits)      xs )
              = {- re-writing as list comprehension -}
                 sum [ (sum . toDigits) x | x <- xs ]
              = {- by definition of (.) -}
                 sum [ sum ( toDigits x ) | x <- xs ]

which should be clear enough.

But you should always add type signatures to your top-level definitions in any case. Here you have

toDigits :: Integral a => a -> [a]

sumDigits :: Integral c => [c] -> c

These provide at least partial documentation for us: toDigits turns an integral number into a list of integral numbers, and sumDigits goes the other way around. How exactly do they do that, these types do not say; but they do provide a general outline of what's going on.

Will Ness
  • 70,110
  • 9
  • 98
  • 181
2

The (.) :: (b -> c) -> (a -> b) -> a -> c is function composition [wiki]: It takes two functions f and g, and for a value x, it will return f (g x). In mathematics this is denoted as f ∘ g: it produces a function that first applies g and then applies f on the result of g.

In this specific case it will thus first apply map (sum . toDigits) before calling sum on the result. and for the mapping itself it will for each item in the list first call toDigits before applying sum. It will thus for a list of numbers determine the sum of the sum of the digits.

Willem Van Onsem
  • 443,496
  • 30
  • 428
  • 555