Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Poslin language embedded

165 views
Skip to first unread message

Antsan

unread,
May 10, 2013, 7:54:34 AM5/10/13
to
I guess this isn't really the best place, but I don't know any better, so I'll do with suboptimal...

When I had postfix notation in school I got the idea of writing a postfix language (Postfiksa Lingvo in Esperanto, short "Poslin"). I hadn't heard of Forth back then and I only had little experience with Lisp, so I just kind of cobbled together a specification (which is lost now) and tried to implement it in Common Lisp but ultimately failed.
In April I got my hands on "Let over Lambda" and after working through that book I realized I now had the tools for implementing it.
So I did. Although I sincerely hope that Poslin is useful for anything practical, my main motivation is curiosity.

You can find it on bitbucket under https://bitbucket.org/thomas_bartscher/poslin/
In the subfolder poslin there are files that make up the standard library of poslin. You can look up definitions there. To the right of almost any line in a definition (between unquoted square brackets) there is a comment showing how the stack looks after doing the operation on that line.
Comments looking like this:
; ( ... -- ... )
describe how the operation that is defined next should modify the stack when called.
; ( n -- n n )
For example is the signature for §, the duplication operation.


A few notes on it's design:

The names I use for operations defined until now are mostly exceedingly short and most likely unreadable. They are intended to be very low level and so they should not take up names that might be useful for users of the language.

Poslin was intended to maintain a tree of stacks where any stack could be called. On that tree any stack would have a name and you could move through that tree, pushing data around.
Defining operations would have been a pure matter of putting operations and values on a stack and then calling that stack to modify the now active stack.

This was inspired by Lisps way of doing this. While implementing Poslin using the approach from "Let over Lambda" I abandoned my original idea of a tree of stacks and did something that felt familiar instead.
As it is possible to open a stack somewhere else but in it's parent stack (by using it as a data structure, moving it somewhere else and then opening it there) I need to keep track of a stack of stacks (called the "path") currently opened, where the top of the path is the stack on which one is currently working. I just got rid of the tree and only retained the path. The hierarchy of stacks is now only implicitly available as stacks saved in variables.

Most operations aren't immediately called when entered but need to be called explicitly. The canonical way to do that is via the operator !.
So to add 1 and 2 you would write
1 2 + !

Defining operations is done via opening a new stack, putting on it all the things you want to do when calling the operation, closing the stack and converting it into an operator.
You cannot use ! to put threads on a stack, for this purpose & is used. &, like !, takes effect immediately. & converts a callable object into a thread, so
+ &
puts the thread associated with '+' onto the stack.
To save an operator one uses @o, which takes three arguments off the stack: An operation environment (I will get to that next), a symbol and a callable object. It converts the callable into a thread and then saves it in the operation environment under the given symbol. The symbol @~o is defined to save the operation in the current operation environment.
The operator [ pushes a fresh stack onto the path, ] pops it off the path and the pushes it onto the new current stack. Both are immediate. ]@ is defined to close a stack and immediately define a new operation.
An example:
foo [ 1 2 + & ]@
Defines an operation foo in the current operation environment that adds the numbers 1 and 2.
If you want to define an immediate operation, use ]i
You can also define operations in a more... common style like this:
bar
{ n arg ; Get one value from the calling stack and save it locall under n
n &v ; Get the value of n
baz & ; call baz
}@ ; define bar

Any stack has two lexical environments: A variable environment, used to save variables (surprise!) and an operation environment. The variable environment basically is a hash table and a parent environment. The operation environment consists of two hash tables, one for associating symbols with operations and one for associating symbols with a boolean value indicating whether the operation associated with that symbol should be called immediately when the symbol is encountered.
Environments are first class objects and can be accessed with ?ev and ?eo respectively. Both operators take a stack as argument. To set the environment of a stack, use @ev and @eo. To look up a variable or operator in an environment, use ?v and ?o, to set it @v and @o. To do the same things with the current environments instead of explicitely needing to supply one, just insert a ~ between the @/? and the rest of the operation name. So, for getting the current variable environment, use @~ev.

To delay an immediate operator, use a quote. Unfortunately I don't understand the interplay between quoting, immediateness and !/& not fully myself (I need to retrace every time), but if I remember correctly right now, the interpreter unquotes, "toplevel" quotes in a stack are removed when converting the stack to a thread and !/& remove one level of quoting (so any quoted object is a callable whose thread returns the quoted object itself).


As poslin libraries are read by the Lisp reader, Lisp read macros should be usable in *.poslin files.
To load a poslin file, use
"path/to/file.poslin" >> !

Poslin has it's own home directory. The path to that home directory currently needs to be set in the environment variable $POSLIN_HOME.
Any running poslin keeps track of it's current directory. This is the value of $POSLIN_HOME at startup and should be a directory containing the files found in the "poslin" folder.

The primary operations of Poslin are defined in startup/prims.lisp
Primary operators are defined via DEFPRIM and DEFNPRIM. If you don't know how Forth handles the program counter and the return stack, don't use DEFNPRIM and stick to DEFPRIM, as a primary operator defined with DEFNPRIM might easily throw Poslin into an infinity loop when defined incorrectly.
Any definition in startup/prims.lisp has at least two lines of comment: One describing what the operation does and one with a stack effect.

The documentation in the doc subfolder is... incomplete and most likely unusable.


Poslin already has a package system. It is implemented in poslin itself, using operation environments as packages and the variable environment to save those packages under a name.
Look into the poslin/package.poslin file for some ideas how to use it. &p and !p are the package equivalents to & and !. p* is used to define a new package. ]@p and }@p are the equivalents to ] and }. p>@ can be used to import an operation from a package into the current operation environment. <p< can be used to import an operation from one package into another.



So, of course I would like some feedback on the language itself.
What kind of documentation do you need and how would it be supplied best?
Are there any features in the language that might be useful?

There is also a problem with the POSLIN-REPL function: When I use
(sb-ext:save-lisp-and-die "poslin" :executable t :toplevel #'poslin-repl)
It seems to forget anything about immediateness, so when entering
1 2 + !
I don't get 3 but
1 2 + !
on the stack. As you can imagine this is quite annoying as it would be very nice to have a standalone REPL. It's also quite strange, as it works just fine when run from the sbcl REPL.
The definition of POSLIN-REPL is in repl/repl.lisp
I know, it's not beatiful, but maybe someone can find out what's wrong.

Max Rottenkolber

unread,
May 10, 2013, 4:28:15 PM5/10/13
to
Very exciting. Although I have zero experience with Forth and family, I
find this very interesting. I don't know enough about the matter to be of
any help but if you want me to try language, I suggest documenting the
core language semantics and vocabulary and supply a practical guide, when
the time is ripe.

For me personally the best way to learn a language is the PCL way of
combining a practical application with a tutorial. The primer on Smug is
another great example of this kind of documentation.

Antsan

unread,
May 11, 2013, 11:14:32 AM5/11/13
to
Hmm, a practical example will be quite hard for a while, but I can try explaining how the standard library is implemented. This would include describing the used primary operations and of course the standard library itself.
An additional advantage would be that it demonstrates what the language is currently capable of and how it works on a basic level. Also I actually have an idea how to do that.

Would that be a helpful tutorial?

Antsan

unread,
May 11, 2013, 6:41:06 PM5/11/13
to
I started writing a tutorial explaining how poslins standard library is implemented.
I am not quite confident in my skills in writing and explaining, so as usual feedback is very welcome.

The tutorial is available in the 'binding' branch of the project. As adding bindings to the language messed up my accessors quite a bit I started writing the standard library from scratch, so some features implemented before are missing right now, but at least lexical scope should work correctly.

Max Rottenkolber

unread,
May 11, 2013, 8:18:24 PM5/11/13
to
> I started writing a tutorial explaining how poslins standard library is
> implemented.

I belive that to be very practical. You also explain how the language
works at the same time so I think its a perfect choice. Drew did the same
thing with smug. See for inspiration:
https://github.com/drewc/smug/blob/master/smug.org

--
Max Rottenkolber
Rottenkolber Software Engineering
http://mr.gy

Antsan

unread,
May 19, 2013, 5:29:21 PM5/19/13
to
The problem with the standalone repl has been solved: Symbols where
checked for immediateness via EQ which of course didn't work as the
reader in the standalone REPL probably was in package #:CL-USER while
all the standard operations where defined in #:POSLIN.
Or, the short version:
(eq poslin::! cl-user::!) => NIL
Environments don't use hash tables anymore for storing immediateness
and stuff and now check for the symbol name instead of checking for
symbol identity, which works as expected (which means it works fine).

A new version of the tutorial (or rather it's first part) is in the
source tree. You can find it in
doc/tutorial/
Redefining the standard library has been delayed until later as all
syntactic sugar is part of the standard library and so the first
definitions look quite esoteric.

I still would like some feedback for the tutorial and the language
itself.
Pointers to other places where I could talk about poslin would be
welcome, too. I still don't think that a newsgroup about Lisp is the
best place for discussing poslin, even when it is implemented on top
of Common Lisp.

Max Rottenkolber

unread,
May 23, 2013, 8:01:27 PM5/23/13
to
> I still would like some feedback for the tutorial and the language
> itself.

I tried going through the tutorial but I have come across some issues.

First of, there are some encoding problems on the bitbucket page when
viewing the tutorial. Minor issue. I also found a type on line 113:

"intimidating. Still, being able to interpret threads can e quite"

This example in section three of the first tutorial:

"Now, let's look at another example.
> __ !
For this we redefine square to be a bit less daunting.
> square [ ~§ & * & ]@
> 3 square !
[ROOT: 9]"

Threw an error for me.

"The value NIL is not of the expected type NUMBER."

I am using the latest version of Clozure CL.

gavino_himself

unread,
May 24, 2013, 12:47:27 AM5/24/13
to
what running programs have been made?

any website creation tools?

and kind of dataabse?

any gains over normal lisp?

what apps have you made in other words?

Antsan

unread,
May 27, 2013, 8:55:31 AM5/27/13
to
Am Freitag, 24. Mai 2013 02:01:27 UTC+2 schrieb Max Rottenkolber:
> > I still would like some feedback for the tutorial and the language
> > itself.
>
> I tried going through the tutorial but I have come across some issues.
>
> First of, there are some encoding problems on the bitbucket page when
> viewing the tutorial. Minor issue.

> I also found a type on line 113:
> "intimidating. Still, being able to interpret threads can e quite"
Thank you, corrected!

> This example in section three of the first tutorial:
>
> "Now, let's look at another example.
> > __ !
> For this we redefine square to be a bit less daunting.
> > square [ ~§ & * & ]@
> > 3 square !
> [ROOT: 9]"
>
> Threw an error for me.
>
> "The value NIL is not of the expected type NUMBER."
> I am using the latest version of Clozure CL.

On SBCL it works fine. Will look into CCL later, I can't really install or use it on the computer I am currently sitting at.

Antsan

unread,
May 27, 2013, 9:12:38 AM5/27/13
to
Ah, you're working on a hammer!
Have you used it for building something useful yet?
Is it possible to use it for chiseling?
Made any woden boxes with it?
How is it better then the usual screwdriver?
In other words: what did you do with it?

Poslin is a work in progress, so: I didn't build anything with it but it's own
standard library. There is no support for anyting fancy. The base language has
to be implemented before I can even start thinking about any of that. No one
would be even able to use
"website creation tools, kind of dataabse"
because basic syntactic sugar is missing.

Poslin is not a Lisp. It doesn't use prefix but postfix and it's not possible
to do functional programming in the base language - if it is possible you will
have to implement it yourself.
There is even less syntax in Poslin then in Lisp because there is no grouping
of operators with operands going on. In Lisp, whether something is considered
an operator is a matter of it's position. In Poslin it's a matter of a symbol
either being defined as immediate or any other object being explicitely told
that it is an operator via another operation that is already running.

Poslin does not have a distinction between macros, functions or special
operators. If you want a Lisp analogy: Basically you are almost always calling
EVAL on anything you want evaluated. This way it is still possible to write
macros, only they aren't distinguishable from basic operations.

Marco Antoniotti

unread,
May 27, 2013, 9:27:19 AM5/27/13
to
On Monday, May 27, 2013 3:12:38 PM UTC+2, Antsan wrote:

> Poslin is not a Lisp. It doesn't use prefix but postfix and it's not possible
> to do functional programming in the base language - if it is possible you will
> have to implement it yourself.

Then, why in the world are you posting here? Just curious.

MA

Max Rottenkolber

unread,
May 27, 2013, 12:09:57 PM5/27/13
to

> Then, why in the world are you posting here? Just curious.

Poslin is implemented in Common Lisp.

Antsan

unread,
May 28, 2013, 2:55:38 AM5/28/13
to
Am Freitag, 24. Mai 2013 02:01:27 UTC+2 schrieb Max Rottenkolber:
> This example in section three of the first tutorial:
> "Now, let's look at another example.
> > __ !
> For this we redefine square to be a bit less daunting.
> > square [ ~§ & * & ]@
> > 3 square !
> [ROOT: 9]"
> Threw an error for me.
> "The value NIL is not of the expected type NUMBER."
> I am using the latest version of Clozure CL.
CCL seems to have #\§ defined as some kind of read macro character. My implementation uses the Lisp reader, so in CCL this macro character needs to be disabled.
Which feature (as in *FEATURES*) can I use to detect that CCL is used? I couldn't find it in the CCL documentation.

Antsan

unread,
May 28, 2013, 2:59:52 AM5/28/13
to
Am Montag, 27. Mai 2013 15:27:19 UTC+2 schrieb Marco Antoniotti:
> Then, why in the world are you posting here? Just curious.
>
> MA
This implementation is done in Common Lisp and I don't know where else to go.
comp.lang.forth seemed like a good idea, but after posting there I think it
wasn't.

Marco Antoniotti

unread,
May 28, 2013, 3:58:50 AM5/28/13
to
I have no problems with discussions of other language implementations in Lisp on c.l.l. (e.g., Python; a long time a go I also remember some posts on f2cl if I am not mistaken). I just felt that the discussion was not related to Lisp, but to Poslin itself.

Cheers
--
MA

Max Rottenkolber

unread,
May 28, 2013, 6:56:28 AM5/28/13
to
> Which feature (as in *FEATURES*) can I use to detect that CCL
> is used? I couldn't find it in the CCL documentation.

There is :OPENMCL, :CCL, :CLOZURE, :CLOZURE-CL, and even version
specific keywords like :CCL-1.9 etc. Chose one. As far as I know
:OPENMCL is there for legacy reasons so go with :CCL or so.

Cheers!

Antsan

unread,
Jun 17, 2013, 2:49:15 AM6/17/13
to
Am Freitag, 24. Mai 2013 02:01:27 UTC+2 schrieb Max Rottenkolber:
'§' is not in the ASCII-Standard. I use the iso-8859-15 encoding while utf8 seems to be used more frequently.
So to avoid problems with encoding, '§' has been replaced with '$'.
0 new messages