Thursday 14 November 2013

Temperature Table

In this example I've taken the temperature table from section 1.2 of Kernighan & Ritchie.  The objective is to write a table of temperatures in Fahrenheit and Centigrade, so we will need to write a loop.  In traditional functional programming style I'm going for some recursion.  I realise this is not the guru way to do this but I'm not a guru.

To write out the results I need another option in the format/2 function.  The placeholder ~6.1f writes a floating point number in a field 6 characters wide with 1 digit after the decimal place.  format/2 doesn't allow a float with no decimal places to I deviate here slightly from K&R.  Also we want the placeholder ~n which just adds a new line to the output.  The documentation  for the format command is in the file which in my machine is saved at C:/Program Files/erl5.10.2/lib/stdlib-1.19.2/doc/pdf/stflib-1.19.2.pdf

Hence it is nice to round up all the PDF files into a documents folder.

Incidentally, who thought of the option to "hide file extension on known file types" and, more importantly, why would anyone want to do this?

The conversion is calculated so:

   Celsius = (5.0/9.0)*(Fahr-32.0),

Now, identifier starting with an upper case character can be assigned values.  They are not variables because you can't vary them - for example you can't say

     Celsius = Celsius + 20.0.

They can be assigned values once like this:

     Celsius = 20.0

Or they can be assigned values when they are arguments to a function and  you call the function.  This is what puzzled me when I started reading up on functional programming - - if you can't re-assign a value how can you do any computation?  Answer: values get assigned when functions are called.

Identifiers that start with a lower case letter are atoms - these can be passed around willy nilly and they evaluate to themselves, they are just like symbols in Lisp.

Anyway the line to displays the result goes:

   io:format("~6.1f ~6.1f~n", [Fahr, Celsius]),

We want to loop up to some Upper temperature figure, adding some Step figure to our starting temperature each time.  To get the loop to work we put the important bits in a function called, say, tempTableLoop:

tempTableLoop(Fahr, Step, Upper) ->
   Celsius = (5.0/9.0)*(Fahr-32.0),
   io:format("~6.1f ~6.1f~n", [Fahr, Celsius])

and then to make the function repeat we can call it again, with the appropriate alteration to the first argument, the Fahrenheit figure:

   tempTableLoop(Fahr+Step, Step, Upper)

Obviously we also want the loop to stop, so check that we are still within the Upper limit by checking Fahr against Upper, in an if... expression:

    if 
Fahr =< Upper ->
       Celsius = (5.0/9.0)*(Fahr-32.0),
       io:format("~6.1f ~6.1f~n", [Fahr, Celsius]),
       tempTableLoop(Fahr+Step, Step, Upper);
    end.

The end statement there just closes the if contruction.  Also we need to provide the alternative branch for the if, for the case when we do finally go over the limit - we don't need to do anything so we just return the
atom ok.

Then our main/0 function can just start the loop function with the initial value, and the complete script looks like this:

%%blank, remember
main([]) ->
    tempTableLoop(0.0, 20.0, 300.0).

tempTableLoop(Fahr, Step, Upper) ->
    if 
Fahr =< Upper ->
       Celsius = (5.0/9.0)*(Fahr-32.0),
       io:format("~6.1f ~6.1f~n", [Fahr, Celsius]),
       tempTableLoop(Fahr+Step, Step, Upper);
true ->
       ok
    end.

The alternatives to the if statement are separated by semicolons.

I don't think you can define the looping function inside the main function as you might in Scheme say.

Anyway:

C:\Users\polly\Erlang>escript temperature.erl
   0.0  -17.8
  20.0   -6.7
  40.0    4.4
  60.0   15.6
  80.0   26.7
 100.0   37.8
 120.0   48.9
 140.0   60.0
 160.0   71.1
 180.0   82.2
 200.0   93.3
 220.0  104.4
 240.0  115.6
 260.0  126.7
 280.0  137.8
 300.0  148.9

Cool:-)

No comments:

Post a Comment