I was recently faced with the following code which is simple but provided the perfect example to practice some Haskell.

I needed to calculate how many IPs there are in a subnet based just on the CIDR provided. The concept is simple, the CIDR indicates how many bits must match between a route and a destination to determine if a route should be taken.

A typical subnet in a home setup might be something like: which means the first 24 bits must match, giving you a subnet range of>, or 256 addresses. However, the network (first) and broadcast (last) addresses are generally unusable, which means the actual usable range is> or 254 addresses.

So, the answer should be simple: numips = (32-cidr)^2 - 2.

However, there are two special cases, a direct route (cidr of 32) which has one matching IP. and a point to point route (cidr of 31) which has 2 matching IP’s. Our algorithm above would return -2 and 0 for these special cases, which is less than ideal.

The C++ implementation is certainly not difficult:

int countips(int cidr)
  switch (cidr)
    case 32:
      return 1;
    case 31:
      return 2;
      return (1<< (32-cidr)) -2; //Use a bitshift to simulate a power of 2 in C

However, the point of this article is Haskell’s pattern matching with guards, which does make this look a lot cleaner, in my opinion. Patterns match from top to bottom, and the first match is the one returned. The algorithmic nature of a functional programming language is perfect for something like this:

ipcount cidr 
       | cidr == 32    = 1
       | cidr == 31    = 2
       | cidr > 0      = 2^(32-cidr) - 2
ipcount _              = 0
Each symbol introduces a pattern guard, if the guard matches, that code branch is executed. It is very similar to our switch based implementation above. The second case with a _ for the parameter name indicates a wild card, so anything at all (including a string or whatever) that does not match the first version will match the wild card version and return 0.

I know this is a trivially simple example for people with a background in Haskell, so I would appreciate it if anyone with more experience wants to add to this example or clean up something I messed up.