UP | HOME

Map and Filter on Lists

This is the level of attention to details and of understanding of subtleties that is required for a decent Functional Programming (and this is why it takes 10,000 hours to master).

There is a deep connection captured by the fact that map, filter and concat could be expressed directly in the list-comprehension notation, which goes back to the Set Theory.

These are generalizations of fundamental, if not universal notions (of the mind of an observer).

The fact that the List type is at the core of Functional Programming and has a special treatment (syntactic sugars, built-in special names of the Constructors) is not a coincidence.

It is (an instance of) Functor and Maybe and Monoid and Monad, and a list of ordered pairs (so-called aList) is a universal lookup-table.

One, it seems, like the old-timers, should program with Lists. The discipline will pay back in clarity, brevity, deeper understanding of the problem domain and better, simpler models.

Lists

Most of the time our intuitions about a List as of something long, and it escapes our attention that it could be either empty or just a singleton.

This particular aspect is what the Maybe type captures.

Another fundamental aspect is that once a single value becomes an element of a list it could be only accessed within a list, through the List ADT’s interface.

This corresponds to the mathematical notion of a Functor, which maps mathematical structures, without tearing them apart.

This is not just a metaphor, partially applied map yields a function from a List to a List, so it literally “maps a function” f: a -> b into that function of the type [b] -> [b].

> :type map (+1)
map (+1) :: Num b => [b] -> [b]

Identity and associativity “laws” has to be preserved by any implementation of fmap.

In pseudo-haskell notation:

map id      = id
map (g . f) = map g . map f

This, in turn, is connected with the fact that (++) is associative

(xs ++ ys) ++ zs = xs ++ (ys ++ zs)

which captures the universal fact that one can “put together” pieces of the same structure taken apart in any order.

(h . g) . f = h . (g . f)

is the same notion of putting functions together (as pieces of the same pipeline).

Just as heads and tails of lists must match, domains and codomains have to match too.

Associative property is just a generalization of a universal pattern about linear structures. Addition could be seen as “linear”.

Map

So, this is a generalized notion of modifying (or transforming) a value embedded into some structure.

  • List comprehension

      map f xs = [f x | x <- xs]
    
  • The classic definition

      map f []     = []
      map f (x:xs) = f x : map f xs
    

Just as structures could be nested, maps can be nested too.

fmap (fmap f)

is a common idiom.

These could be different fmaps - the inner of a Maybe, and the outer of a List, lets say.

Filter

This is a generalized notion of selection, of such that, of defining a subset or a sub-class.

  • Hudak’s style with where, common to maths
filter p (x : xs) = if p x then x : rest else rest
  where
    rest = filter p xs
  • List comprehensions Even more declarative (but not the most), set idiomatic, suggests mathematical notions of such that, and provided p x.
filter p (x : xs) = [x | x <- xs, p x]
  • Hutton’s style, with guards, OR (disjoint union) branching
filter :: (a -> Bool) -> [a] -> [a]
filter p [] = []
filter p (x : xs)
  | p x       = x : filter p xs
  | otherwise = filter p xs
  • Ultimately declarative “logical” and “operational”
filter p = fst $ List.partition p
  • Bird’s style - concatMap, uses list as Maybe
filter p = concat . map (test p)
  where
    test p x = if p x then [x] else []

Here one could see the “empty/non-emopty” aspect of a List (captured in the Maybe type).

Not coincidentally, concat after map are used in one of several definitions of the List Monad, where concat is join.

Concat

This captures the generalized notion of collapsing of a nested structures (one level at a time).

  • List comprehensions

      concat xss = [x | xs <- xss, x <- xs ]
    
  • Bird’s style

    concat []       = []
    concat (xs:xss) = xs ++ concat xss
    

Author: <schiptsov@gmail.com>

Email: lngnmn2@yahoo.com

Created: 2023-08-08 Tue 18:42

Emacs 29.1.50 (Org mode 9.7-pre)