Re: Add nested-function support in a language the based on a stack-machine

Kaz Kylheku <157-073-9834@kylheku.com>
Tue, 13 Mar 2018 03:02:15 +0000 (UTC)

          From comp.compilers

Related articles
Re: language design after Algol 60, was Add nested-function support martin@gkc.org.uk (Martin Ward) (2018-03-27)
Re: language design after Algol 60, was Add nested-function support anton@mips.complang.tuwien.ac.at (2018-03-30)
Re: language design after Algol 60, was Add nested-function support martin@gkc.org.uk (Martin Ward) (2018-04-06)
Re: language design after Algol 60, was Add nested-function support derek@_NOSPAM_knosof.co.uk (Derek M. Jones) (2018-04-08)
Re: language design after Algol 60, was Add nested-function support gneuner2@comcast.net (George Neuner) (2018-04-09)
Re: language design after Algol 60, was Add nested-function support anton@mips.complang.tuwien.ac.at (2018-04-10)
Re: language design after Algol 60, was Add nested-function support derek@_NOSPAM_knosof.co.uk (Derek M. Jones) (2018-04-10)
[19 later articles]
| List of all articles for this month |

From: Kaz Kylheku <157-073-9834@kylheku.com>
Newsgroups: comp.compilers
Date: Tue, 13 Mar 2018 03:02:15 +0000 (UTC)
Organization: Aioe.org NNTP Server
References: <6effed5e-6c90-f5f4-0c80-a03c61fd2127@gkc.org.uk> 18-03-042
Injection-Info: gal.iecc.com; posting-host="news.iecc.com:2001:470:1f07:1126:0:676f:7373:6970"; logging-data="58895"; mail-complaints-to="abuse@iecc.com"
Keywords: code, design
Posted-Date: 13 Mar 2018 15:31:18 EDT

On 2018-03-12, Martin Ward <martin@gkc.org.uk> wrote:
> On 06/03/18 19:02, john wrote:
>> Hypothetical question: Algol60 call by name was a mistake. They
>> intended an elegant definition of call by reference and didn't realize
>> until Jensen's device what they'd done. If they'd done what they
>> intended and we didn't have to invent thunks, how would programming
>> languages be different? -John
>
> Lets go along with the theory that they intended call by reference
> and did not realise that what they had was different until
> Jenson's device was invented. What happened next (hypothetically!)
> was that the language designers realised two things:
>
> (1) Call by name is mathematically, semantically, simpler
> than call by reference
>
> (2) Call by reference is much easier to implement than call by name.
> Call by name requires significant effort to implement.
>
> The designers decided to go with call by name because it produces
> a mathematically simpler language, even at the expense of greater
> effort to implement the compiler.


On the Roseta Code wiki site there is this programming task:


https://rosettacode.org/wiki/Man_or_boy_test


The aim of the task is "Imitate Knuth's example in Algol 60 in another
language, as far as possible".


I did this in my TXR Lisp dialect to a greater extent than the other
solutions, IMHO.


https://rosettacode.org/wiki/Man_or_boy_test#TXR


I implemented a "defun-cbn" macro which is like defun, but
creates a call-by-name function. I also implemented "labels-cbn"
macro for binding lexical functions, also with call-by-name
arguments.


The solution then looks like a nearly expression-for-expression
translation of the Algol:


    (defun-cbn A (k x1 x2 x3 x4 x5)
        (let ((k k))
            (labels-cbn (B ()
                                        (dec k)
                                        (set B (set A (A k (B) x1 x2 x3 x4))))
                (if (<= k 0)
                    (set A (+ x4 x5))
                    (B))))) ;; value of (B) correctly discarded here!


    (prinl (A 10 1 -1 -1 1 0))


The code for these macros is given there, and explained.
Thunks are just objects with lambdas for getting and setting
values. To pass an expression like (foo bar) by name,
which might denote a modifiablke place, it becomes.


Basically the thunk mechanism is simulated with objects that contain
getter/setter lambdas. The function calls are transformed such that their
argument expressions are wrapped in constructors of thunk objects, and then in
the bodies the references are transformed into accessors to these thunks.


There is a bit of a cheat. (defun-cbn foo (...) ...) in fact defines a macro
called foo, and not a function. It also defines a hidden function with a
machine-generated name. The macro transforms the arguments and then calls the
hidden function. This is a cheat because of course macros aren't functions;
they can't be indirected upon with apply, mapcar and so on.


> The result was an explosion of productive research and development
> in compilers and language implementation.
>
> Since that time, language designers have become very cautious and timid
> in specifying powerful new language features and compiler research
> has stagnated.


That's because machines have gotten faster and memories bigger!


Perversely, when memories get bigger, all the interesting stuff
gets a lot slower, because it has exponential complexity.


Approaches that could cut it for production use due to resource limtations that
constrained the input sizes suddenly turn into toys.


I'm only half joking; could that be part of it?


> So to answer your hypothetical question: how would programming language
> be different if the designers of Algol 60 had decided to put
> implementation convenience above mathematical simplicity
> and expressive power in the language?


I suspect that wouldn't because all that call by name stuff business is
basically just an alteration of lazy evaluation semantics into supporting
mutation.


Lazy evaluation means that when we call (f x), x isn't evaluated now; its value
isn't needed yet. Implementation-wise, we pass down something which allows
access to x.


If x is immutable, than that something is a simple lambda that
provides read-only access.


If we don't need the laziness to be implicit in the language, we can
use (delay x) to create a promise of the value of x, and (force p)
to later force the value out of the promise object at the point
where we need it.


If we have discovered lambda as a way of obtaining lazy evaluation
(i.e. implementing delay and force) adding another lambda to also enable the
assignment of a new value to x is just a footnote. We add a second
method (stuff p) to stuff a new value into the promise.
The caller's x put into (delay x) is overwritten and so it goes.


--
TXR Programming Lanuage: http://nongnu.org/txr
Music DIY Mailing List: http://www.kylheku.com/diy
ADA MP-1 Mailing List: http://www.kylheku.com/mp1


Post a followup to this message

Return to the comp.compilers page.
Search the comp.compilers archives again.