Going for a fast-prototype Lisp based language

Started by
29 comments, last by HairyTroll 18 years, 3 months ago
I'm trying to come up with a rapid prototyping language that is easy for the Blitz crowd to understand. The code below shows a rather simple example. It renders a 10x10 matrix of cubes in OpenGL, assigns each cube a random color and then rotates each cube around the x, y, and z axis's by ~1 degree a second. In addition the viewer is able to pan, zoom and rotate the camera around these cubes. My question is, does your head explode when reading this code or can you get the basic flow and intent just by reading it, without any comments or documentation?

(defun rm-rotating-cubes ()
  (let ((width 320) (height 200)
	(button-state nil))
    (init-objects)

    (sdl::with-init ()
      (sdl::window width height :flags (list sdl::sdl-opengl))
      (rm::with-engine ((rm::get-hwnd) width height) root-node

	(let ((cubes nil))
	  (setf cubes (loop for i from 0 to 10
			    append (loop for j from 0 to 10
					 collect (new-mob :script (defscript ()
								      (rotate-mob actor 1.0 1.0 1.0))
							  :primitives (rm::new-box -1.0 -1.0 -1.0
										   1.0 1.0 1.0
										   (random 1.0) (random 1.0) (random 1.0)
										   :cx (* i 3.5) :cy (* j 3.5) :cz 0)))))
	  (add-actor root-node cubes :union t :compute-center t))
	(rm::set-default-scene root-node width height)

	(sdl:with-events
	  (:quit t)
	  (:keydown (state scancode key mod unicode)
		    (when (equal key 'sdl::SDLK-ESCAPE)
		      (sdl::quitevent)))
	  (:mousemotion (state x y xrel yrel)
			(rm::aux-handle-motion root-node button-state x y width height))
	  (:mousebuttondown (button state x y)
			    (setf button-state (rm::aux-handle-buttons root-node button x y width height)))
	  (:mousebuttonup (button state x y)
			  (setf button-state nil))
	  (:idle
	   (update-all)))))))
Advertisement
Even though I'm still trying to find some parts of my exploded head, I think it's a very nice expample.
A few parts I don't understand:

  • ((cubes nil)) why not (cubes nil)?

  • What's the 't'?

  • Also I just can't get used to identifiers with hyphens [smile].


Quote:Original post by darookie

  • ((cubes nil)) why not (cubes nil)?

  • What's the 't'?

  • Also I just can't get used to identifiers with hyphens [smile].



Good questions :)

LET creates local variables. The reason why it is ((cubes nil)) and not (cubes nil) is because LET allows more than one variable to be defined at the same time. So, for example:

(let ((var-1 1)      (var-2 2)      (var-300 "String Here."))   (things that use the variables go here)   (here too))


As for the 't'. Well, (QUIT: ) is run whenever a quit event is received. And the code only exits when (QUIT: ) returns true. And in Lisp, T is true - actually, anything other that NIL is TRUE in Lisp, so I could as well have put (QUIT: 'EXITING-BYE-BYE). For this example, the application will exit on any quit event.
Hey HairyTroll,
Are you using any existing language or writing your own?

(plugging my own work)

I've been working on a lisp-based scripting language for the past month with maximal simplicity in mind. I've tried to clean up all the warts and onions, making things as easy for the unintiated as possible.

A few things I've changed:
- declare closures with 'fn' (instead of 'lambda')
- no setf, setq, only set
- all functions are generic methods (so you can overload without any hassle)
- overloaded operators for datatypes (+ works on numbers and vectors, no need for vec+)
- alternative 'let' syntax: (let (i 10) (...code...)) and (let ((i 10)) (...code..)) both work
- simpler loop constructs
(while [predicate] )
(foreach [item] in [container] [code)
(for [var] from [start-val] to [end-val] )
- easier syntax for optional and variable-number arguments:
(defun f (x [y 0] ... r) (list x y r))
Here y is an optional argument that defaults to 0, and r catches all
arguments passed after r.
- everything is an object, but there's no additional boilerplate OO code (like java or C++)
- a class based object system (so that C++ objects can be treated as lisp objects)
- An extremely easy C++ interface.

Most of my changes were inspired by goo (which has nice features but is horrible to read) and arc (which never materialized).

I think even with the above changes, lisp code looks messy and unstructured to the eye of a C++ programmer. I'd welcome any further suggestions to make the language easier to comprehend.

-Alex
Quote:Original post by cypherx
Hey HairyTroll,
Are you using any existing language or writing your own?


I'm currently working in Emacs,SLIME and Lispworks.

Quote:Original post by cypherx
I've been working on a lisp-based scripting language for the past month with maximal simplicity in mind. I've tried to clean up all the warts and onions, making things as easy for the unintiated as possible.


I'm hesitant to try and define a whole new language. I've been working on trying to abstract away as much of the game making fluff as I can. It would be great to have a C++ interface though. Right now most Lisps only interface to a C API.

It's a pity about Arc as I think Paul Graham really knows his stuff. I'll have to take a look at goo.

I do think that well thought-out Lisp code can be easier to read than C++, especially when templates become involved.

I would respond, but my head exploded.

I don't have anything constructive to say, except that I don't think LISP-like languages are at all easy to grasp if you only have a Basic/C++ sort of background. That's not a criticism of the language you have there, just a comment on the difference between that and what I normally use.
Kylotan,
I think LISP-ish languages are hard at first because you're missing all the visual anchors you depend on when reading a language with syntax. Much of lisp's power arises from all the code being represented as a list...but this can be nightmarish to read.

I think this is one of the biggest barriers to lisp's acceptance. It's not just "too many parens"...LISP requires you to read code differently (with less visual hints) than other languages.

That's why I'm trying to stuff as much syntactic sugar into my pseudo-lisp as possible. Underneath everything is a list, but it needn't look that way to the coder.

Nope, it looks like Lisp to me with your own library bindings. Was there something revolutionary about this other than that it might be a Lisp that actually might really work?

[0] Ignore this-code-doesn't-work-and-your-lisp-interpreter-is-terribly-broken?
[1] Accept this-code-doesn't-work-and-your-list-interpreter-is-probably-broken?
[2] Cross your fingers and try to continue?
[3] ABORT

? 3

SORRY.

? 3

SORRY

? 0

SORRY

? 2

OK.
Are you aware of Fluxus? I don't use it myself, but I'm aware of it because of my interest in VJ and synthesis software. It's geared towards visual musical performance (via live coding) instead of game prototyping, but there's a lot of overlap between the two fields. It probably has a lot in common with what you're trying to accomplish here. Just thought I'id point it out for you, on the off chance that you're unfamiliar with it already.

-bodisiw
-bodisiw
My head doesn't explode when reading it but it's annoying having to figure out what the magic umbers are for. Abstract those into meaningful concepts and it will be nicer.

Also, in my experience, emacs tabbed code that gets an ugly distance horizontally can almost certainly be refactored into something cleaner (and left oriented).

This topic is closed to new replies.

Advertisement