Succeeding dinosaurs, was Re: Communication with the no-functional world.

Ana Maria Abrao ana@ufu.br
Wed, 11 Feb 1998 23:14:05 +0000


Neil Leslie wrote:

> Sadly, you must wait for an asteroid to hit the planet before you can
> expect any real progress.
> 

The mail wasn't address to me, but I would like to say a word or two
about its contents. I don't think that it is very difficult to make
people change their minds. A few years ago, electrical engineers would
sneer at the prospect of using anything different from libraries in
Fortran. Today, they will give away their wives and sons, in order to
keep their copies of Mathlab and Mathematica. If there were good graphic
libraries, statistic libraries, symbolic manipulation libraries, why do
you think that people wouldn't use it? People likes glorified
calculators. Offer them big-mac a  calculator, and they will follow you.

You could reply that people wouldn't write these libraries in Clean. I
think they would. First of all,  people who write symbolic maniputators
and statistical packages are fond of Math. Clean looks like Math. I live
in a small town, in the middle of nowhere, but even here, there are a
lot of people writing software in Clean. They like to write programs
which are concise (a few pages), easy to understand, and do a lot of
interesting things. A small list:

-- As I told, Dr Luciano Lima is a composer. He devised a way to analyse
scores in order to capture the style of his fellow composers, and
generate variations in MIDI. Thus, his MIND Music Composer Lab is able
to write music in the style of Bach, Chopin, Beethoven, etc. His E-mail
is dreams@nanet.com.br. 

-- Mr Cassio Xavier wrote an automated Applet generator. His system
works directly with the Java Machine.  He tryed to make his programs
very small, and easy to understand. I asked his permission to attach the
Constant pool handler, and the code generator to this mail, so you can
see how powerful Clean is.

-- Dr Antonio Costa, Helena, and Paulo are prepairing a partial
rendering of Siegfried in multimedia. Although they are handling the
animations in Visual Prolog, the MIDI is generated by Dr. Luciano's
system.

-- Luis Claudio Theodoro is writing a system simmilar to Cassio's Applet
generator. Nobody saw his system up to now. But he says that it is much
better than Cassio's Apgen. Prof. Luis Claudio is professor at CUNIT.
The address of CUNIT is http://www.facintr.com.br/sec.html.

-- Dr Alcimar wrote small theorem provers in Clean. His ordered linear
resolution prover fits in 100 lines! He explores lazy evaluation to
write an infinite stream of environments, which he filters for
contradiction. The search function fits in two lines:

Search i [w:ws]= [w:Search i1 (rs++ws)]
where { (i1, rs)= Resolvents i w};

Three lines are enough to filter for contradictions:

Start= finalValue (fst ((filter contradiction env) !! 1))
where { contradiction (e, []) = True;
        contradiction _ = False}

There are many other cute things in Alcimar's program. What I like best
is the way he got around the necessity of rewriting the relevant rules.
He submited his program to the Journal of Functional programming. If the
referees think that small is beautiful, you will see his theorem prover
in that Journal. But if they think that one hundred line is not a real
world application, you can email him for a pre-print: alcimar@ufu.br. By
the way, Dr Alcimar works with Biomedical engineering. He is writing
theorem provers only to warm up, in order to tackle an expert system
which recognizes electro-myographic signals.

All this activity is happening in the middle of nowhere. I am sure that
in countries like Spain, France, United States, Italy, and Greece people
are writing software much better than my collegues. I suppose that, when
they start pouring out this software, the age of mammals will arrive.

By the way, I like best the Greek original of your sentence: Alopex men
polla oide, hustix  de hen kalon. Translation: The fox knows many
tricks, but the hedgehog knows a good one.

Well, here is Cassio's Code generator, which drives his Apgen. 

// Handling of the types necessary for representing
// the Constant pool and the code of the Java VM.
implementation module types; // in file types.icl
import StdEnv;

:: TPool =  Utf8 String | Class  Int | Ref (Char, Int, Int) | Str  Int;

:: Asm= B  [Int] |  INT Int | DOUBLE Int | FIELD(String, String) |
		LDC  String  | N String | CLASS String |
		CALL(Char, Char, String, String, String);

// Let's extend the class (==) to handle the pool.
instance == TPool
where {
	(==)  (Utf8 x) (Utf8  y) = x == y;
	(==)  (Class  x) (Class  y) = x == y;
	(==)  (Ref x) (Ref y) = x == y;
	(==)  (Str  x) (Str y) = x == y;
	(==)  _ _ =  False};

// Given an object in the constant pool, 
// getIndex finds its index.
getIndex :: TPool [TPool] -> Int;
getIndex  i []=  ~1;
getIndex  i [j:r]= if (i== j) ((length r)+1) (getIndex i  r);

// addIndex adds an object to the constant pool.
// It returns the modified pool and the index of
// the object.
addIndex  :: TPool [TPool] -> ([TPool], Int);
addIndex  n pool = if (j>0)  (pool, j) ([n:pool], (length pool)+1) 
where {j= getIndex  n pool};

// addC adds a Class to the pool.
addC :: String [TPool] -> ([TPool], Int);
addC x pool= if (j>0) (pool, j) ([Class  i: newPool], length newPool+1)
where {	(newPool,i)= addIndex (Utf8 x) pool;  
	j= getIndex (Class  i) newPool };

// cString adds a string to the pool.
cString :: String ([TPool], String) -> ([TPool], String);
cString x (p, c) = ([Str(i-1), Utf8  x:p], c+++{toChar 18, toChar i}) 
where { i= length p+2};

definition module types;  // in file types.dcl
import StdEnv;

:: TPool =  Utf8 String |  Class  Int | Ref (Char, Int, Int) | Str  Int;

:: Asm=	B  [Int] | INT Int | DOUBLE Int | FIELD(String, String) |
	LDC  String  | N String | CLASS String |
	CALL(Char, Char, String, String, String);

instance == TPool;

getIndex :: TPool [TPool] -> Int;
addIndex  :: TPool [TPool] -> ([TPool], Int);

cString :: String ([TPool], String) -> ([TPool], String);

addC :: String [TPool] -> ([TPool], Int);

//=================
// Code generation and building the pool
implementation module pool; // File- pool.icl
import StdEnv, types, asm;

$ = toChar;
Hi x= toChar((x  / 65536)  / 256);
Lo x= toChar((x / 65536) mod 256);
hi x= toChar((x mod 65536)  / 256);
lo x= toChar((x mod 65536) mod 256);
	
codeGen :: [Asm] ([TPool], String) -> ([TPool], String);
codeGen []  pc= pc;
codeGen [LDC str:r]  pc = codeGen r  (cString str pc);
codeGen [N x:r] (p, c)= codeGen r (q, c+++{hi i, lo i}) 
   where { (q, i)= addIndex (Utf8 x) p};
codeGen [INT i:r]  (p, c) = codeGen r (p, c+++{hi  i, lo  i});
codeGen [DOUBLE  i:r]  (p, c) = 
    codeGen r (p, c+++{Hi  i,  Lo  i,  hi  i, lo  i});
codeGen [CLASS x: r] (p, c)= codeGen r  (q, c+++{hi i, lo i})  
    where { (q, i)= addC x p};
codeGen [B bs:r]  (p,c) = codeGen r  (p, c+++{toChar x \\ x <- bs});
codeGen [CALL(kind, call , super, name, descriptor):r]  (pool, c) 
  #(pool, isuper) =addC super pool;
   (pool, iname)= addIndex (Utf8 name) pool;
   (pool, itype)= addIndex (Utf8 descriptor) pool;
   (pool, inametype)= addIndex (Ref ($12, iname, itype)) pool;
   (pool, i)= addIndex (Ref(kind, isuper, inametype)) pool
= codeGen r (pool, c+++{call, hi i, lo i}); 
codeGen [FIELD(name, descr): r] (p, c) 
 # (pool, iname)= addIndex (Utf8 name) p;
   (pool, idescr)= addIndex (Utf8 descr) pool
= codeGen r (pool, c+++{$0, $0, hi iname, lo iname, 
                   hi idescr, lo idescr, $0, $0});

mkPool :: [TPool] String -> String;
mkPool xs vPool= foldr (+++) vPool [f x\\x <- (reverse xs)]
where {	f (Utf8 s)= {$1, hi sz, lo sz}+++s where {sz= size s};
	f (Class i) = {$7, hi i, lo i}; 
	f (Ref(call, i,j))= {call, hi i, lo i, hi j, lo j};
   	f (Str i) = {$8, hi i, lo i}}

//File- pool.dcl
definition module pool;
import	  StdEnv, types;

codeGen :: [Asm] ([TPool], String) -> ([TPool], String);
mkPool :: [TPool]  String-> String;


//=================================
// Generates an Applet.
implementation module genClass; // File- genClass.icl
import StdEnv, types, pool, asm;

$ = toChar;

Applet :: String  [[Asm]] -> String;
Applet this [fields: methods]= 
   javaClass (CLASS "java/applet/Applet") (CLASS this) fields methods;
 
javaClass super  this  fields  methods
 # version= {$0xCA, $0xFE, $0xBA, $0xBE, $0, $3, $0, $0x2D};
  (pool, mCount)= codeGen [INT (length methods)] ([], ""); 
  iCount= INT 0;  // interface count
  (pool, fCount)= codeGen [INT (length fields)] (pool, ""); 
  (pool, head)= codeGen [INT 1, this, super, iCount] (pool, "");
  (pool, fieldCode)= codeGen fields (pool ,fCount);
  (pool, theCode)= addMethods methods (pool, mCount);
  (_, poolSize)= codeGen [INT (length pool+1)] ([], "");
  constantPool= poolSize +++(mkPool pool  head)
 = version+++constantPool +++fieldCode+++theCode+++{$0, $0};

addMethod pool  [access, name, descriptor:linesOfCode]
 # (pool, theCode)= codeGen linesOfCode (pool, "");
   (codeSIZ, attSIZ) = (size theCode, size theCode+12);
   (pool, theCode)= codeGen [INT 0, INT 0]  (pool, theCode);
   (pool, methodHead)=
 codeGen [access, name, descriptor,  INT 1,N "Code",
	 DOUBLE attSIZ,  INT 50,  INT 10, DOUBLE codeSIZ] 
	(pool, "")
= (pool, methodHead +++theCode );

addMethods  [] (pool, c)= (pool, c);
addMethods [method:more] (pool, c)= 
    addMethods more (newPool, c+++methodCode)
where { (newPool, methodCode)= addMethod pool method };


//File- genClass.dcl
definition module genClass;

import	  types;

Applet :: String [[Asm]] -> String;



//=========== THE BYTE CODE =======
implementation module asm;
import StdEnv, types;

M :: Char;
M= toChar 10;

F :: Char;
F = toChar 10;

VIRTUAL :: Char;
VIRTUAL= toChar 182;

SPECIAL:: Char;
SPECIAL= toChar 183;

STATIC :: Char;
STATIC= toChar 184;

vStatic :: Char;
vStatic =  toChar 178;

vField :: Char;
vField= toChar  180;

aLoad_  :: Int -> Asm;
aLoad_  0= B [0x2a]; 
aLoad_  1= B [0x2b];
aLoad_  2= B [0x2c];
aLoad_  3= B [0x2d];

Bipush :: Int  -> Asm;
Bipush x = B[0x10, x];

Return :: Asm;
Return= B [0xb1];

// ...  etc. Here Cassio list the 255 bytecodes of the Java VM.
// I will spare you from this boring list.


// AppGen interacts with a user, who draws objects
// in an environment similar to Corel Draw. From 
// the interaction, the system builds a calling to
// the function Applet. Here is an example of
// such a calling:

Applet  "helloWorld" 
  [ [],
    [ INT 1,
      N  "<init>",
      N  "()V",
      aLoad_ 0,
      CALL(M, SPECIAL, "java/applet/Applet", "<init>", "()V"),
      Return],
  [  INT  (publicACC), 
     N "paint",
     N  "(Ljava/awt/Graphics;)V",
     aLoad_ 1,
     LDC "Hello, Paul!",
     Bipush 20,
     Bipush 30,
     CALL(M, VIRTUAL, "java/awt/Graphics", 
            "drawString", "(Ljava/lang/String;II)V"),
     Return]];

Cassio is coming here next week. I will ask him to put his program
in our home page. If he agrees, you can examine the whole of it.