Skip to content
Robert Peszek edited this page Sep 17, 2013 · 1 revision

Functional Programming benefits from different code organization than a typical OO code. Fpiglet code looks cleaner, if the style is adjusted to something more oriented towards functions than methods. This style may look strange to developers with used to OO, but it is worth adjusting to.

Here are the rules Fpiglet tries to impose on itself.
The same rules should benefit programs using Fpiglet library. Following these rules makes code more declarative and easier to read.

1. Use curried functions for declarative functional code, use methods for imperative code. Minimize imperative.

Details: Objects are often reduced to role of supporting structures. Programs do not interact using methods defined on FunList, Just(Maybe), Left, Right (Either). Rather, they use closure libraries to interact with these objects.

Why: In this Groovy code:

list.collect{it*it} //confusing OO code

collect is a second class citizen, it is owned by the list.

In Fpiglet code:

map(POWER(_,2)) << list //clear separation of data from manipulation

map is first class citizen, it lives independently of data. Data and manipulation of data become decoupled.

In these rare cases, where data and manipulation need to be coupled, Fpiglet code can simply partially apply data on the manipulation to achieve OO equivalent. Curried functions are simply more powerful than OO methods.

Programmers who want to start thinking functionally need to think of input-function-output chains. OO methods do not help in such thinking.

Exception: Defining concepts:

Things like Type Classes are not part of Groovy language. There is a need for some other way to descibe a concept like Functor or Monad. Example: FunctorDescription is currently an abstract class and probably will become an interface in the future.

Exception: Getters:

Getters are often used to define Closures/functions.

Exception: DSL:

Curried functions are convenient for writing DSL, such code is unlikely to be pure functional.

2. Separate (decouple) functional code from imperative code (stronger version of 1).

Coding and Testing is so much different between functional and imperative that is make a lot of sense to keep these apart. Haskell separates out the unpure, in Groovy it makes more sense to separate out the pure (as there will be much less of it).

3. Group function definitions in Groovy classes using static properties.

Fpiglet often places such classes in packages containing word 'functions'

Example:

package fpig.funlist.functions

class BaseFL {
  def Closure foldL = f ...
  def Closure reduceL = f ...
  def Closure filter = f ...
  def Closure map = f ...
  ...
}

defines basic list functions.

This approach mimics Haskell modules. OO code organization is less useful in functional programming.

4. Use static imports (implied from 3).

Example:

import static fpig.common.functions.FpigBase.*
import static fpig.groovylist.asfunlist.functions.BaseForLists.*

Closure sumAll = reduceL PLUS

This allows the program to pick-and-choose which groups of functions it needs. Again this is similar to importing modules in Haskell and works well with functions.

5. Use composition of curried functions.

This may not solve all the problems but for many it will result in cleaner more readable code. Example: Fpiglet syntax DSL _if_ >> _then_ >> _else_, as well as, eval << where DSL are internally implemented using composition of curried functions.

5b. Avoid using loops.#

Unless there is a very good reason to have them.

4c. Minimize the use of any meta-programming.

Functional programming using function composition, curried functions, and concepts like Functors or Monads is often a better alternative.
The benefit is readable, clean code on both ends (implementation is as readable as client code)!

6. Make it a very distant cousin.

Prefer reusing existing functions over creating new closures. Example:

def add3_GroovyStyle = {it -> 3 + it} 
  
def add3_FpigletStyle = PLUST(3)

using lots of it may imply that that a better solution, one using curried function composition more, is overlooked. This is similar to Haskell, where programmers new to function composition use lots of lambdas.

Also notice, in the above example, that Groovy version is imperative, Fpiglet version is declarative.