-
Notifications
You must be signed in to change notification settings - Fork 3
ApplicativePolymorphism
Applicative type mapping is defined by extending abstract class
fpig.concepts.ApplicativeDescription
This class requires implementing FunctorDescription
methods (Applicatives are Functors) and in addition the following 2 closures:
pure - closure that places elements in applicative context
ap - closure that transforms applicative functions to functions working on applicatives.
You can think of lists as Applicative:
-
pure
needs to place single element in a list in some way, that could be simply[a]
or maybe[a,a,a,...]
-
ap
needs to be able to take a list of functions (closures)[f1,f2,..]
and apply these list to a list of values[v1,v2,..]
in some way.
To be a real applicative you cannot just implement pure
and ap
anyway you like (this is not OO programming any more ;).
You have to obey the applicative laws:
ap(pure(f), ax) '==' fmap(f, ax)
ap(pure(ID), ax) '==' ax
ap(pure(f), pure(x)) '==' pure(f x)
ap(af, pure(x)) '==' ap(pure(FpigBase.apply(x)), af)
In the above 'laws'
ax
, af
denote applicative values or functions.
x
, f
represent 'regular' (not mapped) values and functions.
FpigBase.apply(x, g)
is the same as g(x)
.
I am using '==' to indicate that these are the same 'things' no matter what f,x,ax,af
are.
MonadDescription
can be converted to ApplicativeDescription
by wrapping it in MonadAsApplicative
class (see MonadPolymorphism for more details).
All monads are applicative, but there is one non-monadic example which stands out. Lists (FunList) can be defined as applicative in 2 different ways. One way is by being a non-deterministic computation monad, the other by being a 'zip applicative' implemented in
fpig.funlist.functions.FunListZipApplicative
The ap
function for FunListMonad works by applying list of functions to list of values as in a way that results in a list of all possible combinations.
The ap
function for FunListZipApplicative works by applying list of functions to list of values by 'zipping' or applying n-th function to the n-th value.
You can see examples for applicative applied in the following unit tests:
fun.by_example.FunctionalLists_ExpoTests
fun.by_example.EitherInsteadOfExceptions_ExpoTests
fun.by_example.MaybeInsteadOfNull_ExpoTests
Applicative is really a high-level combinator library. Applicative allows to 'lift' functions defined for 'regular' (not mapped) objects to functions working on applicatives. For example, we can map *
(TIMES) from integers to lists of integers:
ApplicativeDescription fa = FunListZipApplicative.instance
BaseA a = BaseA.getInstance(fa)
def data1 = f ([10, 1, 2])
def data2 = f ([1,2,3,4])
def res = a.zipWith(TIMES, data1, data2)
And as you can see there is a library BaseA
of functions which work polymorphically on anything that is applicative.