I have always been fascinated by the Fibonacci series. However, lately I have grown a obnoxious feeling whenever a fibonacci function is being demoed. The beauty of fibonacci function is its simplicity and the amazing love affair from nature, but the bottom line is that it is simple. Now it is OK to find this example in a programming text book as an illustration to teach the concept of functions, recursions, or the concept of recursion/loop equivalence, or the idea of caching, however, lately it has been used more as a demonstration of new programming language or language features. The first few times I find it silly. Then it keeps coming back and sometime the presentation will emphasize so much that the dominant impression I received is -- now I know how to write fibonacci function!

Recently I watched a Perl 6 presentation where a significant chunk of time is spent in demonstrating how Fibonacci functions can be written in Perl 6. Perl is one of my favorite language, but because of this love, I become extremely sensitive on talks that I felt wrong. To avoid unnecessary flame, let me admit this is more a problem of my own -- my own syndrome. I know that, but I need do something to ease my symptom, so I decided to demonstrate the ultimate Fibonacci language syntax:

include : sequence.def page : test $call define_sequence fib: 0, 1, a0+a1 print "fib(10) = " , fib(10), "

"

With the usual compile and run cycle:

$ mydef_page -mperl test.def PAGE: test --> [./test.pl] $ perl test.pl fib(10) = 55

Is your language more expressive/declarative than this?

For people who are not familiar, I am writing a Perl program in a meta layer called MyDef. MyDef is not limited in writing perl program. I write C, JavaScript, PHP in them as well. If I may pique your interest, there is a documentation: MyDef

Behind the scene

The point I want to demonstrate is that it is often not necessary to replace with a new language to obtain certain higher level features that you dreamed of or desire. All we need realize is we can separate the programming into a lower language layer and an upper lexical layer. Before this separation, a programmer are confronted with one context. Under one context, we worry about expressiveness and precision at the same time, but they are intrinsically conflicting. So a programming language who try to catering both ends are in a dilemma -- which is captured in the waterbed theory. But why the waterbed theory doesn't cause trouble in our daily life? That is because our mind switch contexts all the time. We have no problem thinking in algorithm with abstract data with no type, then in a second, we have no problem comprehending bits in an integer context. So my hypothesis is by separating out the context in programming, we can manage code with both the higher level expressive end and the lower level precision end. MyDef is a pure lexical layer. Basic structures are text lines and indented blocks. Its dominant syntax is a line starting with "$keyword" to hint the programmer the switch of context. At this lexical layer, implementing higher level syntax is easy -- as easy as we invent slangs in school (which in linguistics, it is the dominant force behind language evolution). At higher level, we do not worry about precision, we isolate ourselves from the lower level grease. In my example, I just think about how to best describe a sequence. Then, in a split second, I can switch to lower level context where I look at the compiled code or how I would actually implement it in the lower level language -- Perl in this case. At this context, I do not mind the verbosity of the language but only mind its precision. In an analogy to my daily life, if I popped open my engine hood, I would not care about the grease. Then to bridge between the higher level and the lower level, it is merely a text manipulation.

Implementation

I am going to show you how I implemented my sequence syntax. Be warned that you will encounter engine parts that you are not familiar with, but be assured that they are not difficult once you get to know them.

[ show ] Under the engine hood --

perlcode : define_sequence $if $param=~/(\w+):\s*(.*)/ my $name=$1 my @tlist=split /,\s*/, $2 my $n=$#tlist my @output inject_function($name, ['$n'], \@output) push @output, "\$global \%$name\_hash" push @output, "if(\$n<0){die \" Usage: fib(n)\

\ ";}" push @output, "\$n = int(\$n)" push @output, "\$if exists \$$name\_hash{\$n}" push @output, "SOURCE_INDENT" push @output, "return \$$name\_hash{\$n}" push @output, "SOURCE_DEDENT" $for $i=0:$n push @output, "\$elif \$n==$i" push @output, "SOURCE_INDENT" push @output, "return $tlist[$i]" push @output, "SOURCE_DEDENT" push @output, "\$else" push @output, "SOURCE_INDENT" my @t=split /\b(a\d+)\b/, $tlist[$n] $foreach $t in @t $if $t=~/^a(\d+)/ my $i=$n-$1 $t= "$name(\$n-$i)" my $t=join('', @t) push @output, "my \$t=$t" push @output, "\$$name\_hash{\$n}=\$t" push @output, "return \$t" push @output, "SOURCE_DEDENT" Not difficult. I implemented in half an hour and so can you. You may notice I even threw in hash caching for efficiency. Any idioms, security caution, or design patterns that you know how to write in the low level code, you can implement them here. This is under the engine hood, do not mind the grease.

Check code result at lower level context

At upper lexical level, we write code in the way we think, and we make guesses to comprehend what the code is trying to do. However, the way it works in our daily life is we have mechanism to receive feedbacks on whether our high-level syntax reaches its target or whether our high-level guesses are correct. To do this is mult-layer programming, we need visit the code at the lower level -- no need to hesitate, it is just the usual code we have been dealing with before the layer separation.

use strict; our %fib_hash; sub fib { my ($n) = @_; if($n<0){die "Usage: fib(n)

" ;}; $n = int($n); if(exists $fib_hash{$n}){ return $fib_hash{$n}; } elsif($n==0){ return 0; } elsif($n==1){ return 1; } else{ my $t=fib($n-2)+fib($n-1); $fib_hash{$n}=$t; return $t; } } print "fib(10) = " , fib(10), "

" ;

You have been working with these code before. Now equipped with your higher-level comprehension, this code is even easier to grasp.

More than fibonacci

Once we grasped the higher level slang, we may expand its usage. I hope you realize that I did not just invent an higher level syntax for fibonacci sequence, I implemented a general sequence function generator. Following are examples to help:

include : sequence.def page : test $call define_sequence, Even: 0, a0+2 $sumcode(10) print Even(i+1), " " print "

" $call define_sequence, Geom: 1, a0*2 $sumcode(10) print Geom(i+1), " " print "

" $call define_sequence, Factorial: 1, a0*$n $sumcode(10) print Factorial(i+1), " " print "

" $call define_sequence, A: "recursive" , "I know (" .a0. ") $n" $sumcode(5) print A(i+1), "

"

Follow the same compile and run cycle:

$ mydef_page -mperl test.def PAGE: test --> [./test.pl] $ perl test.pl 2 4 6 8 10 12 14 16 18 20 2 4 8 16 32 64 128 256 512 1024 1 2 6 24 120 720 5040 40320 362880 3628800 I know (recursive) 1 I know (I know (recursive) 1) 2 I know (I know (I know (recursive) 1) 2) 3 I know (I know (I know (I know (recursive) 1) 2) 3) 4 I know (I know (I know (I know (I know (recursive) 1) 2) 3) 4) 5

Convince me that I need a functional language for them! Note that I am not saying functional programming language are no good, but the reason won't come from the ability to write fibonacci functions.

PS: The code is an exercise. I do not think this powerful sequence expression has much real world usage other than make homeworks for our children. Saying that, I am dismissing the values of those demonstrations that use Fibonacci to show off the power of their feature/language. They need do more than that.

[ show ] Implementations in C

PS2: To highlight that the solution is not language specific, I implemented in C as well: perlcode : define_sequence $if $param=~/(\w+):\s*(.*)/ my $name=$1 my @tlist=split /,\s*/, $2 my $n=$#tlist my @output inject_function($name, [ "n" ], \@output) my $type= "int" $if $tlist[0]=~/\./ $type= "double" push @output, "\$return_type $type" push @output, "\$if n<0" push @output, "SOURCE_INDENT" push @output, "return 0" push @output, "SOURCE_DEDENT" $for $i=0:$n push @output, "\$elif n==$i" push @output, "SOURCE_INDENT" push @output, "return $tlist[$i]" push @output, "SOURCE_DEDENT" push @output, "\$else" push @output, "SOURCE_INDENT" my @t=split /\b(a\d+)\b/, $tlist[$n] $foreach $t in @t $if $t=~/^a(\d+)/ my $i=$n-$1 $t= "$name(n-$i)" my $t=join('', @t) push @output, "return $t" push @output, "SOURCE_DEDENT" C is more low level, so I omited caching in this example. However, it is omited to keep the code simple. It is not difficult. If we switch to C++, then we can use map in the STL. Or we could add a simple custom hash function. With that under the hood, let's demo: include : sequence.def page : test , basic_frame $call define_sequence, Even: 0, a0+2 $sumcode(10) printf "%d " , Even(i+1) $print $call define_sequence, Geom: 1.0, a0/2 $sumcode(10) printf "%g " , Geom(i+1) $print $call define_sequence Factorial: 1, a0*n $sumcode(10) printf "%d " , Factorial(i+1) $print Succinct as before! $ mydef_page -mc test.def PAGE: test --> [./test.c] $ gcc -o test test.c && ./test 2 4 6 8 10 12 14 16 18 20 0.5 0.25 0.125 0.0625 0.03125 0.015625 0.0078125 0.00390625 0.00195312 0.000976562 1 2 6 24 120 720 5040 40320 362880 3628800 Works! C is statically typed, so it is more complicated to add polymorphism, but it is not difficult in principle. As demo, I let it guess between integer and floating point, and as you see, it works. Since now it is in C, I can't help myself to consider efficiency. For simple sequences, let's implement the code with loops. Compare the following code with the recursion code above. I always fail to understand why people nowadays want to avoid loops. perlcode : define_sequence $if $param=~/(\w+):\s*(.*)/ my $name=$1 my @tlist=split /,\s*/, $2 my $n=$#tlist my @output inject_function($name, [ "n" ], \@output) my $type= "int" $if $tlist[0]=~/\./ $type= "double" push @output, "\$return_type $type" push @output, "\$if n<0" push @output, "SOURCE_INDENT" push @output, "return 0" push @output, "SOURCE_DEDENT" $for $i=0:$n push @output, "\$elif n==$i" push @output, "SOURCE_INDENT" push @output, "return $tlist[$i]" push @output, "SOURCE_DEDENT" push @output, "\$else" push @output, "SOURCE_INDENT" $if $n>0 push @output, "\$local $type a[$n]={" .join( "," , @tlist). "}" my $t = pop @tlist my @t=split /\b(a\d+)\b/, $t $foreach $t in @t $if $t=~/^a(\d+)/ $t= "a[$1]" $else $t=~s/n/i/g $t=join('', @t) push @output, "\$for i=$n:n+1" push @output, "SOURCE_INDENT" push @output, "\$local $type t" push @output, "t=$t" #---- update the working memory ---- my $j=0 $for $i=0:$n-1 $j=$i+1 push @output, "a[$i]=a[$j]" push @output, "a[$j]=t" push @output, "SOURCE_DEDENT" push @output, "return t" push @output, "SOURCE_DEDENT" We just swapped the engine! Close the hood, and drive the car as usual!

[ show ] Implementations in Haskell

Fibonacci sequence is the *Hello world* for Haskell, so this post won't be complete without take a look at Haskell. fib 0 = 0 fib 1 = 1 fib n = fib(n-2) + fib(n-1) geom 0 = 1 geom n = geom(n-1) * 2 fac 0 = 1 fac n = n * fac (n-1) rec 0 = "recursive" rec n = "I know (" ++ rec(n-1) ++ ") " ++ show n As advertised! I still think my $call define_sequence fib 0, 1, a0+a1 is superior because it is in one clean line. First, I chose "$call define_sequence" to provide enough context for average programmer to guess the syntax, but it is trivial to shorten that into "$-" (or anything as matter of fact) if shorter typing is ever desired. Second, the remainder of my sequence syntax is essentially bare bone. Third, with MyDef, we know where our engine is and it is only covered by an engine hood. We can easily tune the engine or swap the engine as we have demoed in the C implementation, and we can tune every hardware units in that case. But before some of you start to cry out, I admit that I am not that familiar with Haskell, and I admit Haskell on the surface is quite clean -- at least for this type of car (recursive sequence), and maybe who familiar with Haskell have no problem know where the Haskell engine hood is and be able to tune hardware any time they want. So use your Haskell. I never tried to persuade you otherwise; but in case you have complaints of some sorts, I would like to point out that there is nothing wrong to use MyDef on top of Haskell: page : test type: hs $call define_sequence, fib, 0, 1, a0+a1 $call define_sequence, geom, 1, a0*2 $call define_sequence, fac, 1, a0*n $call define_sequence, rec, "recursive" , "I know (" ++ a0 ++ ") " ++ show n perlcode : define_sequence $if $param=~/(\w+):\s*(.*)/ my $name=$1 my @tlist=split /,\s*/, $2 my $n=$#tlist my @t=split /\b(a\d+)\b/, $tlist[$n] $foreach $t in @t $if $t=~/^a(\d+)/ my $i=$n-$1 $t= "$name(n-$i)" my $t=join('', @t) $for $i=0:$n push @$out, "$name $i = $tlist[$i]

" push @$out, "$name n = $t

" push @$out, "

" Not much different than the implementation in Perl or C, but of course, much simpler. MyDef is simply a translation from what you wanted to write into what you meant to write, at lexical level. To compile: # There is no special module for Haskell as I do not really know Haskell # but the gneral module already can do a lot. $ mydef_page -mgeneral test.def PAGE: test --> [./test.hs] It produces the exact Haskell code shown above.

[ show ] Implementations in Lisp