When I find something interesting and new, I post it here - that's mostly programming, of course, not everything.

Saturday, December 13, 2008

Functions

An Excuse

Well, I decided to gather all the code related to Function class in one "universe" container class, Functions. The other option would be to have a separate "package". I do not see any reason for using packages instead of container classes.

My idea regarding container classes is that it is a theory - we have constants, types, rules, axioms, all in one place. An element of theory is meaningless outside of its theory. A set does not make sense without a Set Theory.

So here we have some kind of "Functions Theory". Since functions are defined on types, which vaguely are like classes, which vaguely are like unlimited sets, we can define set-theory-like notions of Injection and Bijection. A Surjection would be nice to have too, but it has no functional influence on current programming practice: nobody knowingly builds factorsets.

Overview

Three abstract classes are defined: 
  • Function - general functionality;
  • Injection - a special kind of Function, not mapping different values to one;
  • Bijection - invertible Function
and several useful extra classes: 
  • Inclusion, - a Function that includes one set into another; 
  • Id - an identity Function
  • PairsToMap - takes a set of pairs, turns it into a Map;
  • IterableToSet - takes an iterable, turns it into a Set.
Also there are several  static methods. Don't be afraid of static methods, they all belong to Functions Theory, and there's hardly a reason to override or polymorph them in any way.

Function

A Function<X, Y> declares an abstract method Y apply(X x), which obviously determines the function's behavior. In addition, Function has methods for mapping an Iterator, an Iterable, a Collection, a List. Note that there's no method that maps a Set. Why? Because if you apply a Function to a Collection, you can have repeating values.

Method toMap(Set<X) converts a Function into a Map; method forMap(Map<X, Y>) turns a Map into a Function. Static compose(f, g) method composes two Functions.

Injection

Injection is a special kind of Function: it maps different arguments to different values. Not that we can verify it; we just trust the declaration. Since a composition of two Injections is an Injection, this case is taken care of. It is. 

An Injection maps a Set to a Set, so this method is there.

Inclusion is a special kind of Injection: it includes one class (set) into its superclass (superset). It maps a value to itself, casting.

Bijection

Bijection<X, Y> is a special kind of Injection: it has an inverse. So, additionally, it declares a method X unapply(Y). A composition of two Bijections is a Bijection


Here is a sample code, where Schwartzian transform is defined:

/**
* Given a function f, builds another function that for each x
* builds Map.Entry(x, f(x))
*
* @param f function to apply
* @return a function that builds pairs.
*/
public static <X, Y> Bijection<X, Pair<X, Y>> schwartzianTransform(final Function<X, Y> f) {
return new Bijection<X, Pair<X, Y>>() {
public Pair<X, Y> apply(final X x) {
return math.cat.LazyPair.LazyPair(x, f);
}

public X unapply(Pair<X, Y> p) {
return p.x();
}
};
}


Oh, and the code is here.

No comments:

Followers

Subscribe To My Podcast

whos.amung.us