home *** CD-ROM | disk | FTP | other *** search
- Nntp-Posting-Host: hauken.ifi.uio.no
- Newsgroups: comp.lang.functional
- Path: sparky!uunet!mcsun!sunic!aun.uninett.no!nuug!ifi.uio.no!olsson
- From: olsson@ifi.uio.no (Jan Roland Olsson)
- Subject: Run-Time Code Generation ?
- Message-ID: <1992Dec14.152715.6442@ifi.uio.no>
- Organization: Dept. of Informatics, University of Oslo, Norway
- Date: Mon, 14 Dec 1992 15:27:15 GMT
- Lines: 90
- Originator: olsson@hauken.ifi.uio.no
-
-
- Functions that return other functions are common in
- functional programs. The function returned is created
- at run-time and is in strict languages most often
- represented using closures.
-
- In my view, a closure consists of
-
- 1. A pointer to the machine code for a function.
- 2. One or more pointers to "arguments" of the function.
- These arguments may be other closures.
-
- It sometimes happens that the function returned is
- represented by 10 or more closures pointing to each
- other. If the function is not recursive, these closures
- normally form a tree that is isomorphic to the
- expression tree for the right hand side of the
- function definition.
-
- A recursive function may be represented by closures
- that form a directed cyclic graph, where the cycle
- can be introduced with a pointer i.e. a value of
- ref type in ML.
-
- I have a program in Standard ML of New Jersey that
- synthesizes, i.e. writes, function definitions and
- translates them to closures in order to execute them.
-
- This works fine except for the fact that the resulting
- functions execute about twice as slowly as functions
- that are defined by ML source code and compiled.
- Since the functions created at run-time are needed
- over and over again, perhaps even millions of times
- including recursive calls, this is a significant
- performance problem for me.
- Here is a small trivial example that illustrates
- the problem.
-
-
- fun compose 0 F = ( fn X => X )
- | compose N F =
- let val g = compose (N-1) F
- in
- fn X => F ( g X )
- end;
-
-
- val f1 = compose 5 tl;
-
- val f2 = fn X => tl(tl(tl(tl(tl(X)))));
-
-
- The functions f1 and f2 are the same, but calls
- to f1 execute much slower than calls to f2.
-
- What I really would like to have is a built-in
- function
-
- compile : ( 'a -> 'b ) -> ( 'a -> 'b )
-
- which has the same semantics as the identity
- function, but changes the representation of the
- definition of its argument from lots of inter-
- linked closures to pure machine code.
- Since Standard ML of New Jersey stores machine
- code on the heap as garbage collectable byte
- sequences and since the compiler is part of a
- running ML program this seems possible.
-
- Am I the only ML programmer on this planet that
- finds such a function useful ?
-
- Or maybe there are some drawbacks or solutions that
- I have overlooked ?
-
- Or maybe I should use Common Lisp instead, which after
- all has compile built in ? Needing to switch to
- Lisp just for a performance problem like this would
- really be a pity, since ML in my view is a much
- better language and since Standard ML of New Jersey
- is an excellent implementation.
-
-
-
-
-
-
-
-
-
-