Search code examples
haskellcomposition

Is it possible to define patterns of composition in functions or functors?


Consider the following situation. I define a function to process a list of elements by the typical way of doing an operation on the head and recalling the function over the rest of the list. But under certain condition of the element (being negative, being a special character, ...) I change sign on the rest of the list before continuing. Like this:

f [] = []
f (x : xs) 
    | x >= 0      = g x : f xs
    | otherwise   = h x : f (opposite xs)

opposite [] = []
opposite (y : ys) = negate y : opposite ys

As opposite (opposite xs) = xs, I become to the situation of redundant opposite operations, accumulating opposite . opposite . opposite ....

It happens with other operations instead of opposite, any such that the composition with itself is the identity, like reverse.

Is it possible to overcome this situation using functors / monads / applicatives / arrows? (I don't understand well those concepts). What I would like is to be able of defining a property, or a composition pattern, like this:

opposite . opposite  = id    -- or, opposite (opposite y) = y

in order that the compiler or interpreter avoids to calculate the opposite of the opposite (it is possible and simple (native) in some concatenative languages).


Solution

  • You can solve this without any monads, since the logic is quite simple:

    f g h = go False where 
      go _ [] = [] 
      go b (x':xs)
        | x >= 0    = g x : go b xs 
        | otherwise = h x : go (not b) xs
          where x = (if b then negate else id) x'
    

    The body of the go function is almost identical to that of your original f function. The only difference is that go decides whether the element should be negated or not based on the boolean value passed to it from previous calls.