Above, Below, and Beyond Tech Talk

by Rahel Lüthy

May 29, 2015

Partial Function Application in Haskell

Learning myself a Haskell should be for great good, so grasping the basics is essential. I am forcing myself to go slowly, taking baby steps in the REPL.

Today, I came across this really simple example:

map (>10) [1,42,99]

Figuring out that this will give [False,True,True] is not exactly rocket science, but what exactly is this (>10) term? Given that we’re talking about Haskell, it must be a function, right? Also, inferring from the types involved, it must be a function that accepts a Num and returns a Bool. But how does this come about?

Back to more basics – here’s another simple function:

greaterThan :: Int -> Int -> Bool
greaterThan x y = x > y

greaterThan 10 42 -- False

Confusingly, the type signature does not distinguish between parameters and the return type. This has been my most important Haskell epiphany yet: Every function in Haskell actually only takes one parameter

Calling greaterThan 10 42 just looks as if we were passing two parameters, but we’re actually calling the function with one parameter, getting a function from Int -> Bool in return, and then immediately calling this function with the second parameter to get the result. Let’s make this explicit by breaking the call down to the individual steps:

tenGreaterThan = greaterThan 10 -- returns a function with Int -> Bool signature
tenGreaterThan 42 -- returns the final result (still False)

Now back to the (>10) term: Pretty much everything in Haskell is a function, so > is a function, too. It is usually called with infix notation, e.g. 10 > 42, but it can actually be converted to a postfix function by putting it in parenthesis:

(>) 10 42 -- still False

Obviously, we can also partially apply here:

tenGreaterThan = (>) 10
tenGreaterThan 42 -- also still False

Back to our initial example – here it is again:

map (>10) [1,42,99] -- [False,True,True]

Applying (>10) to 42 correctly gives True, but applying (>)10 to 42 did give False in the example before, right? Things that make you go hmmmm…

Turns out the parenthesis are really crucial here! In Haskell there is a syntax called sectioning, which is special for partial application on infix operators. The term (>10) corresponds to a right section, which is equivalent to flip (>) 10. No wonder the semantics seemed flipped!

Long story short: While it is quite intuitive that the (>10) corresponds to a \x -> x > 10 in the initial map example, the magic happens through Haskell’s special sectioning syntax.


May 13, 2015

Java 8 Unsigned Int

When I recently profiled one of our applications, it turned out that a lot of memory was wasted on a huge number of long primitives. They were used to represent IDs, which were originating from a 3rd party text file. Someone must have loved huge numbers, so they chose an ID format that didn’t fit into an int.

Well, while being huge, the IDs were at least always positive. So I was confident that some data massage would allow me to squeeze them into primitive int values eventually. It took me by surprise that Java 8 actually supports unsigned primitives out of the box. Guess we all missed that while wrapping our heads around lambdas and streams, right?

Here’s how it works:

public class UnsignedIntTest {

    @Test
    public void roundTrip() {

        // compile error: 2^32 - 1 is too large for an int
        // int intValue = 4294967295;

        long longValue = (long) Math.pow(2, 32) - 1;
        String longValueAsString = String.valueOf(longValue);

        int unsignedInt = Integer.parseUnsignedInt(longValueAsString);

        long result = Integer.toUnsignedLong(unsignedInt);

        assertEquals(longValue, result);

    }

}

March 22, 2015

JavaFX 3D Line

I have no experience in 3D programming whatsoever. Last week, I took my first steps in JavaFX 3D, but hit a wall when I wanted to draw a line between two points: There is no Line shape! The only out-of-the-box Shape3D classes are Box, Cylinder, Sphere, and MeshView – wow…

Well, it shouldn’t be too difficult to connect the points with a slender cylinder, right?

I was wrong, it took me an embarrassingly long time to get the trigonometry right :-)

Here’s my magic crutch:

public Cylinder createConnection(Point3D origin, Point3D target) {
    Point3D yAxis = new Point3D(0, 1, 0);
    Point3D diff = target.subtract(origin);
    double height = diff.magnitude();

    Point3D mid = target.midpoint(origin);
    Translate moveToMidpoint = new Translate(mid.getX(), mid.getY(), mid.getZ());

    Point3D axisOfRotation = diff.crossProduct(yAxis);
    double angle = Math.acos(diff.normalize().dotProduct(yAxis));
    Rotate rotateAroundCenter = new Rotate(-Math.toDegrees(angle), axisOfRotation);

    Cylinder line = new Cylinder(1, height);

    line.getTransforms().addAll(moveToMidpoint, rotateAroundCenter);

    return line;
}

To illustrate what’s going on, I created a 2D representation of all individual steps, starting off with the creation of the cylinder. By default, its center is placed at the origin:

The moveToMidpoint transformation moves its center to the final location (the yellow midpoint in the above image):

And finally, the rotateAroundCenter transformation corrects the cylinder’s direction:

Obviously, the tricky part is finding the proper axis and angle of rotation. Both are calculated relative to the yAxis because of the cylinder’s initial direction. The axisOfRotation must be perpendicular to the plane defined by the yAxis and the diff vector. To find such a perpendicular vector, we can (by definition) calculate the cross product of the two vectors. In the 2D case, the result is equivalent to the z-axis, but in 3D it may be tilted.

The angle is calculated based on the dot product (aka scalar product) of the two vectors, which is defined by

A • B = |A| |B| cos(alpha)

If A and B are both unit vectors, this becomes

A • B = cos(alpha)

which we can resolve to

alpha = acos(A • B)

That’s it!


Older Posts » Archive