Monday, November 4, 2013

ELENA 2.0 Tutorial: Accumulator factory

In this tutorial we will implement another Rosetta code sample: Accumulator.

Our task is to implement the function which will return another function accumulating passed parameters.

Let’s start with declaring our accumulator function. Note that ELENA is an object-oriented language and any function is in fact an object (or in our case – a symbol).

#symbol EFunction =
{
   eval : x
   [
       ^ self append:x.
   ]
}.

Or we could simplify the code using a generic closure (function symbol):

#symbol EFunction =
 (:x) [ self append:x ].

Note that our code cannot be used stand alone, because we do not declare “append” method. It is in fact an object extension (that’s why it starts with E).

So another function should be declared – it will combine the passed variable (supporting “append” method) with our accumulating function – creating a wrap group object:

#symbol Accumulator = (:aVariable)
    [ Wrap(EFunction, aVariable) ].

To understand how this code works let’s recall what is a group object. In short group object overwrites SELF variable (but not $SELF one). Various group objects do it differently. Wrap one replaces SELF in the extender (the first one) with the content (the second one). To put it another way it wraps the extender around the content: when we call append method, Wrap group object redirects the message to its first member replacing SELF with the second one.

The use case will be the following:

#var x := Accumulator : (Integer new:1).
x:5.

Let’s optimize the code a bit, to allow our symbol accepting constant values as well

#symbol Accumulator =(:anInitialValue)
    [ Wrap(EFunction, Variable new:anInitialValue) ].

So we could drop the variable creating:

#var x := Accumulator : 1.
x:5.

The full code is below:

#define system.
#define system'dynamic.
 
#symbol EFunction = 
    (:x) [ self append:x ].
 
#symbol Accumulator = (:anInitialValue)
    [ Wrap(EFunction, Variable new:anInitialValue) ].
 
#symbol Program =
[
    #var x := Accumulator:1.
 
    x:5.
 
    #var y := Accumulator:3.
 
    console write:(x:2.3r).
].

1 comment:

  1. Code modified to reflect recent syntax change (starting from 1.9.11)

    ReplyDelete