Lisped

A programming language is much like the languages we speak. If a sound is missing from a language, the speakers cant produce that sound. More interesting is the fact that they do not understand the value of that sound. The lives of Chinese people are not any worse because of the inability to say ‘R’. Ditto for the programming languages.

New languages are created by programmers, not by standards. A hacker’s time is very valuable and the language should respect that by getting out of his way. An elegant language takes the user to the most natural solution. Even if it means twisting the standards.

To understand the power of a language you have to learn it. And to learn it you must be convinced about the weakness of your current language. But how can you identify the weakness when you dont know if it is a weakness? The best way is to just take the word of a better hacker. It was when I started reading Paul Graham that I heard about Lisp. I could see people appreciating it, praising it, see it in action but not understand it. It seemed like just a big pile of CARs and CDRs. It took me three months of reading to witness the first glimpse of its power. And it was worth waiting.

Problem: You have to write a function that takes two lists, fun_list (a list of functions) and arg_list (list of arguments). Your function should apply each function in fun_list on every argument in arg_list and return a list containing the list of result of each function.

The C way: What we write and call C++, isnt remotely close to C++. So i wont be calling this C++ code.

First question: How to represent a list of functions? I ll just use vectors. DAMN, now i have to read about the syntax of vector. And how do I represent functions? That too with unknown signature? DAMN again! no problem, I ll just restrict the signature to some predefined value and mention it in my documentation. Or I can define it a template, but how do you do that? DAMN again. The arg_list also has to be defined as a template list.

Lets try Google for syntax issues. Notice that we have already spent a good 10 minutes and we are yet to write a single LOC.

Okay, now that we have gathered all the stuff, lets get on with writing code. Lets start by a simple code and expand it to full form. Lets assume the each function operates on integers and return an integer as well.

#include <vector>
using namespace std;
vector<vector<int>> apply_funcs_to_args(vector<int (*)(int)> fun_list,vector<int> arg_list)
{
      vector res;
      /* some stuff here */
      return res;
}

And I am stuck as I need to confirm the syntax of function pointers. What to do? Back to Google and MSDN.SHEESH, hope somebody is keeping time, this is hard work dude.Now i need a function that will apply a function to the arg_list and return the result. Here it is,

vector<int> apply_func_to_args(int (*f)(int) f,vector<int> arg_list)
{
      int i = 0; vector<int> res;
      for( i = 0 ; i < arg_list.size() ; i++ )
      {
            res.push_back(f(arg_list[i]));
      }
      return res;
}

I have to make sure that this function is defined before apply_funcs_to_args or it will not recognize it. Now my final code becomes,

#include <vector>

using namespace std;
vector<int> apply_func_to_args(int (*f)(int) f,vector<int> arg_list)
{
      int i = 0;
      vector res;
      for( i = 0 ; i < arg_list.size() ; i++ )
      {
            res.push_back(f(arg_list[i]));
      }
      return res;
}
vector<vector<int>> apply_funcs_to_args(vector<ret_type (*)(arg_type)> fun_list,vector<int> arg_list)
{
      int i = 0;
      vector<vector<arg_type>> res;
      for( i = 0 ; i < fun_list.size() ; i++ )
      {
            res.push_back(apply_func_to_args(fun_list[i],arg_list));
      }
      return res;
}

But to make it work with any data type, i have to change it to template.

#include <vector>

using namespace std;
template<class ret_type,class arg_type> vector<ret_type> apply_func_to_args(ret_type (*f)(arg_type),vector<arg_type> arg_list)
{
      int i = 0;
      vector<ret_type> res;
      for( i = 0 ; i < arg_list.size() ; i++)
      {
            res.push_back(f(arg_list[i]));
      }
      return res;
}
template<class ret_type,class arg_type> vector<vector<ret_type>> apply_funcs_to_args(vector<ret_type (*)(arg_type)> fun_list,vector<arg_type> arg_list)
{
      int i = 0;
      vector<vector<arg_type>> res;
      for( i = 0 ; i < fun_list.size() ; i++ )
      {
            res.push_back(apply_func_to_args(fun_list[i],arg_list));
      }
      return res;
}

This code assumes that the return type of every function is same. So how do we handle different return types? We can make a generic class Result and force each function to return a pointer to class inherited from that class? Notice how a language restriction has forced us to propagate a change in some other code. Okay, I am done. Where is my Electra? What! i am not? I have to test it too, well too bad, I am exhausted, maybe tomorrow. Infact I dont want to look at the code again because its too ugly. Let me try Lisp. I can directly jump to writing whatever i am thinking.

(define apply_funcs_to_nums(lambda(fun_list arg_list) (map (lambda (f) (map f arg_list)) f_list) ))

And we are done. Dont believe it? I myself was shocked to see that the code worked on the first run. And it took me not more than 5 minutes to write it and test it (in fact I really didnt have to test it). And I spent the next two days in high fiving everyone just because I was so happy: D. This code is bug free, evident, non-restrictive and makes no assumptions. Its short and its beautiful. Imagine a person who can pull this kind of stunt in every LOC. Do you think such skill can be beaten by scale? Would you be willing to take him on as your competitor? I know I wouldnt.

No related posts.

4 Comments

  1. Sharjeel says:

    One can imagine Adil’s joy after writing those two lines of lisp. After coding them he went to see Girl’s Beach Volleyball Match in LUMS and there all the time he kept saying “Wow! She is BEAUTIFUL! I just love Lisp!”

  2. Adil Saleem says:

    Do not make me spill out your secrets :@

  3. Jonathan Marasko says:

    Dude you are comparing apples and oranges here. Every language has a specific purpose. I am not a big on C++, but C is mostly syntactic sugar on top of assembly language. Try writing systems code in Lisp. I am not putting down Lisp in anyway. Lisp is a brilliant language and almost every language uses ideas from Lisp. Lisp is good only for a certain class of programs. If you really want to do a fair comparison, why not do Lisp vs. Haskell or ML for that matter.

  4. Adil Saleem says:

    Yes, you are right. C is just the high level assembly language. I used C partly because it is understood by most programmers and partly because there were a lot of C users around me demanding the advantages of LISP over C. But perhaps the actual reason was that C was my fav language for a long time :) .

Leave a Reply