Skip to content

ruliana/YoDaFunkta

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

10 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Yo da Funkta!

The simplest possible (but not simpler) functor implementation for Java.

News

2009-10-07 new Polymorphic parametric functors – Same functor name + different parameters = different functors.
2009-10-07 prototype InfiniteList – A list where the elements are generated by the functor as needed. First draft.

Motivation

After wandering throught Jakarta Commons Collections, Jakarta Commons Functor and JGA – Java Generic Algorithms as a nerd myself I thought “Hell! That’s way cool, but I need something simpler to use…”.

You know… “Simple” and “Java” are words that don’t like to stay together. So, throught the use of heavy voodoo and some hocus pocus, I got what I think it’s a nice solution. Very simple to use (but no really simple behind the scenes… oh, well… that’s life).

How to use and what it does?

An example worth a thousand user manuals.

To declare the functor simply create a static method and create the functor. I like to put the functor declaration right above the method, it looks like an odd annotation.


    import static yodafunkta.Functor.f
    .
    .
    .
    private static final Functor length = f("length");
    private static int length(String string) {
        return string == null ? 0 : string.length();
    }

Then you can execute it:


    public void testRun() throws Exception {
        assertEquals(1, length.run("a"));
        assertEquals(4, length.run("test"));
    }

Or use it to mapping (transformations):


    public void testMapping() throws Exception {
        List<String> list = asList("this", "is", "a", "test");
        
        assertEquals(asList(4, 2, 1, 4), length.map(list));
        assertEquals(asList(3, 7, 4), length.map("yet", "another", "test"));
    }

Also, you can declare the functor “on the fly” (Particularly, I prefer to declare it as a constant, but that’s a matter of taste):


    public void testDeclareOnTheFlyAndRun() throws Exception {
        
        Functor myOwnLength = f("length");
        assertEquals(1, myOwnLength.run("a"));
        
        assertEquals(4, f("length").run("test"));
    }

If you have a static method that returns “boolean”, you can use filters:


    // you can use "f" of "functor", they as the same.
    // It's a matter of taste, again.
    import static yodafunkta.Functor.functor
    .
    .
    .
    private static final Functor odd = functor("odd");
    private static boolean odd(int number) {
        return number % 2 == 1;
    }

    public void testFilter() throws Exception {
        List<Integer> list = asList(1, 2, 3, 4, 5, 6);
        
        assertEquals(asList(1, 3, 5), odd.filter(list));
        assertEquals(asList(3, 5, 11, 13), odd.filter(2, 4, 3, 5, 6, 8, 11, 12, 13));
    }

Currying is also supported:


    import static yodafunkta.Functor.f
    .
    .
    .
    private static final Functor greaterThan = f("greaterThan");
    private static final Functor greaterThan4 = f("greaterThan", 4);
    private static boolean greaterThan(int length, String string) {
        return string != null && string.length() > length;
    }

    private static final Functor between = f("between");
    private static final Functor between2and = f("between", 2);
    private static boolean between(Integer min, int max, Integer target) {
        return min < target && target < max;
    }

    public void testCurrying() throws Exception {
        assertTrue(greaterThan4.evaluate("Testa"));
        assertFalse(greaterThan4.evaluate("Test"));

        Functor greaterThan3 = f("greaterThan", 3);
        assertTrue(greaterThan3.evaluate("Testa"));
        assertTrue(greaterThan3.evaluate("Test"));

        assertTrue(between.evaluate(2, 5, 3));
        assertFalse(between.evaluate(2, 5, 6));

        assertTrue(between2and.evaluate(5, 3));
        assertFalse(between2and.evaluate(5, 6));

        Functor between2and5 = between2and.param(5);
        assertTrue(between2and5.evaluate(3));
        assertFalse(between2and5.evaluate(6));
    }

What else?

There are support for combining functor and other smaller niceties. Check the yodafunkta.FunctorTest class for more examples.

Also, some gotchas you might have know:

1. You lose static typing check. There is always a balance between “power” and “safety”, here I choose “power”. IMHO, static type checking it’s not that safe, so, for me, it’s a really small price to pay. But you are not me, it’s better to be warned :)

2. It’s a little slow. Since I made heavy use of reflection, the equivalent functor code is about 5~7x slower than the hard coded version. For a simple transformation of 100K elements, on my machine, the hard coded version took between 25 to 50 milliseconds, the functor version took between 120 to 180 milliseconds. IMHO, unless you need extreme performance, that’s not big issue. But again, that’s me, you might have another opinion.

3. Legal notice: You can copy, modify, use, do-whatever-you-want to this code and you can or cannot give me any credit (I really don’t mind). However, I provide no guarantee nor promises about the code (i.e. use it “as is” at your own risk). Use it if you like it, throw it in the garbage if you don’t like it. :)

Anything else?

I wish you like it. Let me know if you are using it :)

[]s
Ronie Uliana

About

The simplest possible (but not simpler) functor implementation for Java

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages