Thursday, March 22, 2012

Update on anonymous functions

I am an idiot.  I left out perhaps one of the most fun things about anonymous functions: return data.

I'm still getting used to working in a functional way of thinking, but this is perhaps one of the most fun ways to use an anonymous function.  It might be a little be evil, I'm not sure yet, but it's certainly interesting.  take a simple string concatenation:
function getThingie(x) {
  var a = "I would like to buy";
  var b = "for a good price.";
  var c = "nothing";

  if (x == 1) {
    c = "a dog";
  }
  else if (x == 2) {
    c = "a cat";
  }
  else if (x == 3) {
    c = "a bath";
  }

  return a + " " + c + " " + b;
}

If we replace this with an anonymous function it can then look like this:
function getThingie(whatThing) {
  return "I would like to buy " + (function(x) {
    if (x == 1) {
      return "a dog";
    }
    else if (x == 2) {
      return "a cat";
    }
    else if (x == 3) {
      return "a bath";
    }
    else {
      return "nothing";
    }
  })(whatThing) + " for a good price.";
}

I'm not 100% sure which is 'better', but for my money, I find the flow of having the conditional inline as a function more clear. If this were a language like Scala, we could have a match clause here, or a partially applied chain. Ultimately, it puts shit where it goes, and that's my number one rule of programming.  In this case, it means you don't have an assignment somewhere that has a chain of logic that is basically out-of-line of the program flow.  When we read a sentence, we scan along the sentence and piece together information in our head in the order we read it, whether that's left to right or right to left, it's just easier to digest if we don't have to skip around to figure out what is going on in a story, or, in a piece of code.  So, in that way, I think this obeys "put shit where it goes" pretty well.
To give an example, here's one way it might look in Scala:

def getThingie(whatThing) = {
  "I would like to buy " + (x match {
    case 1 => "a dog"
    case 2 => "a cat"
    case 3 => "a bath"
    case _ => "nothing"
  ) + " for a good price"
}

Arguably this would be an interesting case to use a partially applied function:

def mapMeMyPurhcaseItem : PartialFunction[Int, String] = { 
  case 1 => "a dog"
  case 2 => "a cat"
  case 3 => "a bath"
}

def getThingie(whatThing) = {
  return "I would like to buy " + 
    (mapMeMyPurchaseItem(x) getOrElse "nothing") + 
    " for a good price.";
}

Why would you want to do this?  It could be argued that this obeys the "put shit where it goes" rule even better.  The function only returns if the arguments is within the domain of the function, otherwise you must provide an alternative.   It means the fall-through clause is explicit and local so the fall through case isn't hidden inside a function.  Partially applied function are extremely powerful constructs I'm beginning to learn, and I think I'm going to find them to be a good friend in building extremely robust programs, but that's a story for another time!

No comments:

Post a Comment