Inspired by the latest Ruby Quiz: IP to Country: #139, I coded up a utility to map ip addresses to country codes in erlang. It’s available on google-code at http://code.google.com/p/ip2country-erlang/.
Some experiences while making this thing work:
- It took me the better part of six hours to get this running. I suspect if I’d done this with Ruby, I’d have completed an elegant, fast solution in less than a half hour. However I did make this harder for me (see below).
- It uses the in-memory database that Erlang has: mnesia. There’s functions in there to populate the mnesia table with the csv file and then perform lookups on it.
- Higher-order functions is the name of the game. For just about every useful thing from looping down to iteration, to mapping elements of a list. Coming from a non-functional background, I find this very hard to grasp still. Also: non-mutable state. Count +=1 doesn’t work. [So how do you implement a counter? Recurse with a parameter].
- I miss the Ruby Standard Library very very badly. Of all the languages I’ve used, Ruby’s is the most concise and clear and manages to have just about every function you need in there. String manipulation in Erlang esp. is very cumbersome. Somebody probably should port over all the functions asap. lists:join, string:delete, string:delete_if etc. would be invaluable.
- The comma, semi-colons and fullstop craze (along with proper indentation) is sometimes very confusing. The rules are actually easy to remember, but when I nest functions using funs, I find I lose track of where I am and what’s supposed to happen. I started programming this using Aquamacs but it crashed on me midway while using the inbuilt shell. I hate stuff which crashes so I switched to Textmate’s erlang mode which isn’t as functional but does a decent job of parenthesis matching and auto-indent.
- Mnesia is a joy to use. I spent a lot of time just playing around with many examples because it’s fun to make a record, dump it and use list comprehensions to perform selects. It’s way more intuitive than using SQL. Witness this fragment:
qlc:q([X#ip_address_map.country_code || X <- mnesia:table(ip_address_map), X#ip_address_map.range_from =< Ip_address_as_integer, X#ip_address_map.range_to >= Ip_address_as_integer ]).
That actually just says: get the country code for all X where X is an mnesia table of type ip_address_map and where X’s ip_ranges are within range_from and range_to. No SQL and exactly as you’d do within the language.
- It feels very awkward to get Erlang to be a shell scripting language. I’m not sure escript is even supported anymore but it does work. Erlang is not for scripting.
- The whole exercise reminded me of my extreme newbiness. I’ve been dabbling off and on in Erlang for over four months now and still I’m not at a stage where I can code in it off the top of my head (this hasn’t happened before with any language, but admittedly all the others were just procedural ones). The problem is I’m not using it for anything big. That should hopefully change someday. [Not much hope, but does somebody want to hire me to work on erlang or lisp? :-)]
- The erlang mailing lists help a lot. Just being there you soak up a lot of info.
- Concurrent erlang is another ball game altogether.