-
Notifications
You must be signed in to change notification settings - Fork 3
FunctorPolymorphism
Functors can be viewed as higher level of Polymorphism in programming. This blog explains Functors:
http://rpeszek.blogspot.com/2013/05/better-polymorphism-polymorphism-where.html
The functor concept comes from mathematics, but it is a very powerful software development tool. In nutshell, a high level mapping F between types is a (covariant) Functor if:
F(ID) == ID //ID refers to identity function
F( g << f ) == F(g) << F(f) // << refers to function composition
So the simplest way to say it is that Functor is a piece of code that maps things and does not mess up function composition.
Currently the following Type mappings in Fpiglet are identified as functors:
FunList<T> -> List<T> //(applies FunList library to Groovy Lists)
//see FunListToListFunctor class
FunList<Character> -> String //(applies FunList lib to Strings viewed as list of Characters)
//see FunListToStringFunctor class
FunList<String> -> String //(applies FunList lib to tokenized Strings)
//see FunListToTokenizedStringFunctor class
FunList<String> -> InputStream//(applies FunList lib to tokenized Strings)
//see FunListToTokenizedInputStreamFunctor class
(See FunListToString, LazyIO, FunListToGroovyList.)
And this list is likely to grow and include Functor Type mapping to other things like DB interactions.
This allows for easy mapping of all functions defined for FunList to regular Groovy Lists or to Strings, so programs can use functions like reduceL, map or filter directly on Strings or Lists.
The examples of using fuctional list library on Groovy List have been shown on the home page as well as here: FunListToGroovyList. Here is one of them repeated:
assert [5,10,50] == take(3) << filter{it % 5==0} << map{1 + it * it} << (1..10000)
Here is an example which shows functorial programming on Strings:
//count words
def stringFunctions = BaseForTokenizedStrings.forToken(' ')
assert 3 == stringFunctions.foldL(flip (f (PLUS << FIRST(1))), 0) << '12 123 1234567'
Note: curried function (CurriedFunctions) composition works nicely here, the function composed 'to' has more than one parameter!
Instead of predefined shorcuts you can use one of the mapping functions withFunList (or fmap function defined in the corresponding Functor class):
assert [5,10,50] == withFunList(filter {it % 5==0} << map {1 + it*it}) << (1..7)
assert [5,10,50] == fmap(filter {it % 5==0} << map {1 + it*it}) << (1..7)
or
def fmap = FunListToTokenizedStringFunctor.forToken(' ').fmap
assert ['groovy', 'groovy' 'geeks'] == fmap(filter{it.startsWith('g'}) << filter{it.length()>4}) << 'is groovy groovy to geeks'
Pure functional programming in Groovy has to be more of a convention than something the language can enforce. You can view Functor Mapping, or funlistIn funlistOut functions, or the withFunList function as boundaries between pure and un-pure when mixing Fpiglet and OO Groovy.
Developers today miss out on not understanding and not using function composition. If they did not, the term Functor would require no explanation. If you code with fuction composition, then Functor natural step one towards code reuse. In fact, other functional programming concepts oriented at code reuse (like Monads) are Functors too.
Side Note: Some obvious Functors are currently not defined by any explicit Functor class (this may change):
//classic [] Functors:
<T> -> FunList<T> is a Functor with fmap = fpig.funlist.functions.BaseFL.map
<T> -> List<T> is a Functor with fmap = fpig.groovylist.asfunlist.functions.GroovyListAsFunList.map
Another Side Note: Functor class definitions (especially the TypeMapping class) are likely to change. It is hard to design good Type Mapping using Groovy or Java type system.
TypeMappings are currently used for informational purposes only.