Stratus3D

Software Engineering, Web Development and 3D Design

Currying and Partial Application in Elixir

I often forget what currying and partial application are and how they are used, so I am writing this blog post to solidify these concepts in my memory.

###Currying

Currying is when a single function with multiple arguments is converted into multiple functions, each expecting one of the arguments of the original function. For example, we could curry the :erlang.atom_to_binary/2 function in Elixir like this:

> binary_fn = fn(encoding) ->
>     fn(atom) ->
>         :erlang.atom_to_binary(atom, encoding)
>     end
> end
#Function<6.80484245 in :erl_eval.expr/5>

> binary_fn.(:utf8).(:bar)
"bar"

We now have a function that takes the first argument, and returns another function that expects the second. This is currying. As you can imagine there are many possible uses for this. Including partial application…

###Partial Application

Partial application is when you curry a function and pass fewer arguments than the original function expected. Continuing with our atom_to_binary example, this would be partial application:

> atom_to_utf8 = binary_fn.(:utf8)
#Function<6.80484245 in :erl_eval.expr/5>

We now have provide one of the two arguments required to invoke atom_to_binary/2. We receive a new function which we store in atom_to_utf8 variable. This function expects the second argument of atom_to_binary/2 to be passed in. When this function is invoked, it calls atom_to_binary/2 with the values :utf8 (which was passed in earlier) and :foo.

> atom_to_utf8.(:foo)
"foo"

This is partial application. Partial application relies on currying to produce functions that contain references to the arguments that have been provided(via closures) and expect the remaining arguments of the original function.

Currying allows us to break a function down into many functions, and partial application uses currying to create functions with some of the arguments already applied. Both of these concepts are extremely useful. We can, as we did above, create new functions on the fly by providing a subset of the arguments, and we can also pass around the curried functions, providing the arguments they require as those arguments become available. There are quite a few possible uses for currying. I may write another post about currying and closures in Elixir sometime in the future but this is all for today.

Splitting Pipe Delimited Data With Ruby

Today I was working with some pipe delimited data in Ruby and stumbled across some things in Ruby’s String#split method that I thought I would share. My code needed to take data like this and parse it into an array of strings.

Some|Fields|of random|data|1|2|3

Each line of the data looked something like this and had a varying number of fields. Sometimes data would have missing fields:

Some|Fields|of random|data|||3

I figured I would simply split the string based on the pipe character using something like this:

'Some|Fields|of random|data|||3'.split('|') #=> ["Some", "Fields", "of random", "data", "", "", "3"]

This works seems to work fine. Blank fields come across as empty strings. I used the length of the array to determine the number of fields contained in the string. In this case, seven fields of data, the 5th and 6th of which were empty. I thought this would work but I quickly ran into an issue:

'Some|Fields|of random|data|||'.split('|') #=> ["Some", "Fields", "of random", "data"]

Now I had a problem. The string of data contains seven fields, but the last three are empty. After splitting the string on the pipe character we get an array of only 4 items(fields). My program needed to know that there were three empty fields at the end. I did some research and it turns out that Ruby’s String#split method takes an optional second parameter. The second parameter is an integer which limits the number of fields returned. If omitted, all trailing null fields are ignored and not added to the array. If the second argument is a positive integer it limits the number of fields returned. split('|', 0) would return an array with the entire string as the only element. But if the second argument is a negative integer, trailing null fields are added to the array as empty strings. That allows us to do this:

'Some|Fields|of random|data|||'.split('|', -1) #=> ["Some", "Fields", "of random", "data", "", "", ""]

Perfect! Now even with trailing empty fields in our data we are still able to tell how many fields are present.

Ruby’s String#split method makes parsing strings of data very easy. In my case all I needed to do was split the data on every newline, then take the array of strings returned and split each one on the pipe character.

Hope you found this useful!

Website Relaunch

The Stratus3D website was hacked about six months ago and I haven’t had time to put it back up. I rebuilt the site and launched it on 1/1/2014. The new version is simplier than the old one. It also lacks some of the things the old site had such as sections for 3D models and tutorials. The site currently doesn’t have a section dedicated to 3D models and the Blender tutorials are now listed under the blog. I will be working on adding the missing content back to the site over the next couple of months.

Enjoy the website!