
Hi Folks, Recently I had a small epiphany: when creating functions, design them to return functions rather than non-function values (Integer, Bool, list, tuple, etc.). Here's why: Consider a function that returns, say, the integer four ( 4 ). The type of the value returned by the function is this: 4 :: Num a => a That is, the value returned is not a function, it is a number. However, there are advantages to returning a function rather than a number. Recall the composition operator ( . ) Its operands are functions, e.g. (+1) . (*3) In programming, one school of thought is that programs should be written as a chain of function compositions: a . b . c . d . e . f Composition is intimately connected to a branch of mathematics called Category Theory: Category theory is based on composition as a fundamental operation in much the same way that classical set theory is based on the 'element of' or membership relation. ["Category Theory for Computing Science" by Michael Barr and Charles Wells] By designing programs in this fashion--as a chain of compositions--you have Category Theory's vast body of knowledge to help you and give rigor to your programs. Let's revisit the function mentioned above, the one that returns the integer four ( 4 ). If the function were to return the four cloaked in a function then that returned value could be used in a composition. That would very useful. Here's a data type that lifts non-function values to functions: data Lift a = Function a deriving (Show) The constructor ( Function ) is a function, as its type signature shows: Function :: a -> Lift a So rather than returning 4, return Function 4. Here's a function that converts any value to a function: lift :: a -> Lift a lift = Function Thus, lift 4 returns Function 4 Given the Lift data type and the lift function we can now start chaining functions together. Here the value four is lifted and then composed with a successor function: (successor . lift) 4 returns Function 5 where successor is defined as: successor :: Num a => Lift a -> Lift a successor (Function a) = lift (a + 1) Notice that successor returns a function, not a non-function value. Consequently, the result of successor can also be used in a composition. For example, here the value four is lifted, composed with successor, and then square is applied: (square . successor . lift) 4 returns Function 25 where square is defined as: square :: Num a => Lift a -> Lift a square (Function a) = lift (a * a) Once again notice that square also returns a function, not a non-function value. Consequently, the result of square can be used in a composition. At some point we are finished manipulating the value four and want to just see the result, not the result wrapped in a constructor. So we can create a function to return the non-function value: value :: Lift a -> a value (Function a) = a Here's an example: (value . square . successor . lift) 4 returns 25 Comments welcome. /Roger