Sign in to follow this  

lisp minilanguages

This topic is 4373 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I've been thinking about lisp minilanguages again lately, and I'm wondering what are the benifits of them over, say, data structures/classes? As much as I've thought about it, I still won't feel comfortable until I've discussed this with someone who knows a bit more about lisp, and it never hurts to have more dicussions.

Share this post


Link to post
Share on other sites
Quote:
Original post by Roboguy
DSLs can actually be OO, if that's well suited to the problem it's trying to solve. They are used to make solving specific types problems easier.

Actually, I was referring more to the advantages of DSLs over using just plain data. Here's an old example that illustrates what I mean:

(defquest
(hero link)
(objective
(recover princess-zelda))
(difficulty hard))

vs.

quest = Quest(
hero="link",
objective="Zelda",
difficulty=HARD
)

Where 'Quest', in this case, is a data structure (or class, if you prefer).

I'd also like to point out that this isn't meant to be flamebait (as Shannon suggests)--I really do want to know the advantages of DSLs. I've already read a lot about them, but I've found that actually talking to someone about it reveals a lot of information that otherwise wouldn't have been found.

Share this post


Link to post
Share on other sites
Mini-languages allow you to expand the expressivity of data. For instance, let's say that a particular weapon does a certain number of points of damage. So you might have, in your datastructure, a line like Damage = 3. Now, if your RPG has the weapon do different amounts of damage to, say, small, medium, and large monsters, it might look like Damage = {Small = 5, Medium = 4, Large = 3}. But wait! Suppose this particular weapon deals an extra point of damage when you're attacking an ogre named Ed who likes onions? Now things get tricky, and the data structure format gets ugly. What's happening is that the format should be expressive enough to express what you want to express, yet (maybe) shouldn't need to be changed piecemeal to accomodate new types of weapons. So instead you have a line like Damage = function(monster) if monster.type == "ogre" and monster.name = "Ed" and monster.likes("onions") return 4 else return 3 end. Bingo: All the complexity you want, none that you don't want.

Also, suppose that that particular weapon is The Ed Sword. There are similar swords, such as the Ted sword and the Bill sword, which are meant for attacking other ogres with different names. You could have a separate entry for each and manually keep all of them updated together, or you could have your minilanguage produce multiple weapons, given a list of names.

That's the ideal. Of course, many consider Little Languages to be an antipattern in certain workflow situations. Think long and hard as to whether you actually need one. They can be difficult to understand, difficult to integrate into tools, and difficult to maintain when underlying engine structure changes.

Share this post


Link to post
Share on other sites
Quote:
Original post by Sneftel
They can be difficult to understand, difficult to integrate into tools


Strange... I often find myself making tools with the explicit purpose of interpreting some "little language" and producing some output resource file. :s (Of course, I suppose those languages are generally littler than the ones that can be produced by Lisping, unless you want to write a full-blown compiler...)

Share this post


Link to post
Share on other sites
Quote:

a)what's a DSL?

Domain-Specific Language.

Quote:

b)isn't the advantage of the Lisp version is that code is data

Yes. Domain-Specific Languages can be created in lisp based on this concept (using macros). I'm not sure what you mean by this, though:
Quote:

, where as the "class" below has to be compiled to some form of binary or byte code?

Share this post


Link to post
Share on other sites
Quote:
Original post by Zahlman
Strange... I often find myself making tools with the explicit purpose of interpreting some "little language" and producing some output resource file. :s (Of course, I suppose those languages are generally littler than the ones that can be produced by Lisping, unless you want to write a full-blown compiler...)

I'm mostly referring to the tools which produce the LL code, rather than those which process it. Level editors, for example, where you're coding triggers. The problem is, triggers expressed as a simple, un-language-like set of data can be easily produced with GUI tools, represented with GUI tools, and linted. Once you get into LLs, though, the effect of an attribute cannot be reliably inferred from the code of the attribute. This can lead to a situation I've seen several times: a GUI which (bad) chokes on, or (semi-bad) ignores, any code outside of that conforming to a set of templates which it produces and can parse (think "go to level X" and "give item Y"). For everything else, you either edit the level file manually, or inject code using the keyboard in the level editor. And after you do either of these things, the editor basically folds its arms and refuses to lint your level or give you useful arrows showing the destination of manually coded doors.

Share this post


Link to post
Share on other sites
Quote:

Mini-languages allow you to expand the expressivity of data.

How would this be better than custom file format?

Quote:

But wait! Suppose this particular weapon deals an extra point of damage when you're attacking an ogre named Ed who likes onions? Now things get tricky, and the data structure format gets ugly. What's happening is that the format should be expressive enough to express what you want to express, yet (maybe) shouldn't need to be changed piecemeal to accomodate new types of weapons. So instead you have a line like Damage = function(monster) if monster.type == "ogre" and monster.name = "Ed" and monster.likes("onions") return 4 else return 3 end. Bingo: All the complexity you want, none that you don't want.

I would think it would be easier to just use polymorphism, since that's what it looks like you're doing.

Share this post


Link to post
Share on other sites
Quote:
Original post by bytecoder
Quote:

Mini-languages allow you to expand the expressivity of data.

How would this be better than custom file format?

It's not really a question of format. Using your native language's parser saves you the trouble of writing your own parser, if you like. But a mini-language can be a custom file format.

Quote:

I would think it would be easier to just use polymorphism, since that's what it looks like you're doing.

That depends on what you mean by "use polymorphism".

Share this post


Link to post
Share on other sites
Quote:

It's not really a question of format. Using your native language's parser saves you the trouble of writing your own parser, if you like. But a mini-language can be a custom file format.

Correct me if I'm wrong, but isn't expressiveness directly tied to format? Oh, and I'm talking about DSLs in lisp using macros, to clarify :)

Quote:

That depends on what you mean by "use polymorphism".

As in function pointers/virtual functions. Now that I look at it, that doesn't seem to matter. I'm not sure how the example you give is related to lisp DSLs, though.

Share this post


Link to post
Share on other sites
Quote:
Original post by bytecoder
Correct me if I'm wrong, but isn't expressiveness directly tied to format?

Nah, not really. Your format is equally expressive whether it ends statements with semicolons or carriage returns. The important part is whether the format supports language-like features--conditionals, loops, things of that sort.
Quote:

As in function pointers/virtual functions. Now that I look at it, that doesn't seem to matter. I'm not sure how the example you give is related to lisp DSLs, though.

A DSL allows you to add the Ed Sword and its brothers to your world in a natural manner which doesn't require you to change the underlying format, the underlying parser, or the underlying engine structure. To get equivalent behavior would require you to change two or three of these things, and to spread your desired functionality across different modules.

Share this post


Link to post
Share on other sites
Quote:

Nah, not really. Your format is equally expressive whether it ends statements with semicolons or carriage returns. The important part is whether the format supports language-like features--conditionals, loops, things of that sort.

Ok, I see.

Quote:


A DSL allows you to add the Ed Sword and its brothers to your world in a natural manner which doesn't require you to change the underlying format, the underlying parser, or the underlying engine structure. To get equivalent behavior would require you to change two or three of these things, and to spread your desired functionality across different modules.

I'm not sure I understand. If you didn't design the DSL with that in mind, you'd have to change it, just as you would if you didn't design the data structures with that in mind.

Share this post


Link to post
Share on other sites
Quote:
Original post by Sneftel
[...]I'm mostly referring to the tools which produce the LL code, rather than those which process it. Level editors, for example, where you're coding triggers. The problem is, triggers expressed as a simple, un-language-like set of data can be easily produced with GUI tools, represented with GUI tools, and linted. Once you get into LLs, though, the effect of an attribute cannot be reliably inferred from the code of the attribute. This can lead to a situation I've seen several times: a GUI which (bad) chokes on, or (semi-bad) ignores, any code outside of that conforming to a set of templates which it produces and can parse (think "go to level X" and "give item Y"). For everything else, you either edit the level file manually, or inject code using the keyboard in the level editor. And after you do either of these things, the editor basically folds its arms and refuses to lint your level or give you useful arrows showing the destination of manually coded doors.
I think the reason editors usually can't handle custom script well is that IME most game designers (whether professional or amateur) don't bother with reading existing material on something before they attempt to implement it, excepting graphics to some degree. If a person read 'The Dragon Book'(Compilers: Principles, Techniques, and Tools ISBN: 0201100886) before trying to implement a DSL (in a not-highest-level language, or something more appropriate for doing so in a Lisp-like), I think they would have no trouble making the editor itself work with the 'Real Script' and reserve the 'GUI Scripter' solely for easing the task of generating commonly-used patterns.

Share this post


Link to post
Share on other sites
Quote:
Original post by bytecoder
I'm not sure I understand. If you didn't design the DSL with that in mind, you'd have to change it, just as you would if you didn't design the data structures with that in mind.

To some extent, yeah. In this situation, you need to design with the thought that the damage done by a weapon might depend on the monster involved. But that's a pretty logical assumption in the first place, much more logical than assuming that a weapon might need to care about onions.

Here's another example: A weapon which only does damage to monsters whose armor class is a prime number. Trivial to implement using a DSL; requires a "OnlyDoesDamageToPrimeArmorClasses" flag otherwise.

Share this post


Link to post
Share on other sites
Quote:
Original post by bytecoder
Quote:

b)isn't the advantage of the Lisp version is that code is data

Yes. Domain-Specific Languages can be created in lisp based on this concept (using macros). I'm not sure what you mean by this, though:
Quote:

, where as the "class" below has to be compiled to some form of binary or byte code?

sorry i misunderstood. i thought that was the representation of a C++ class. discussion over my head. don't mind me.

Share this post


Link to post
Share on other sites
Quote:

Here's another example: A weapon which only does damage to monsters whose armor class is a prime number. Trivial to implement using a DSL; requires a "OnlyDoesDamageToPrimeArmorClasses" flag otherwise.

In this situation, it really makes more sense to consider 'damage' as a separate entity. For example, such a situation could be handled like this:

data DamageExclude:
exlude_func:callable
damage:int

type DamageNormal = int
type Damage = DamageNormal | DamageExcludeClass

Share this post


Link to post
Share on other sites
Quote:
Original post by bytecoder
In this situation, it really makes more sense to consider 'damage' as a separate entity.

I don't know that I'd agree with that; a level designer would be unlikely to consider a weapon's damage as a separate object from the weapon itself.

Share this post


Link to post
Share on other sites
Quote:
Original post by Sneftel
Quote:
Original post by bytecoder
In this situation, it really makes more sense to consider 'damage' as a separate entity.

I don't know that I'd agree with that; a level designer would be unlikely to consider a weapon's damage as a separate object from the weapon itself.

I didn't mean that literally. I just figured it would help, as you seemed to be merging the damage type with the overall structure containing it.

Share this post


Link to post
Share on other sites
I'm actually in the process of writing a sort of mini-lisp interpreter in C++. See my journal. http://www.gamedev.net/community/forums/mod/journal/journal.asp?jn=339729 Ignore the growing Jesus controversy.

Share this post


Link to post
Share on other sites
Quote:
Original post by Deyja
I'm actually in the process of writing a sort of mini-lisp interpreter in C++. See my journal. http://www.gamedev.net/community/forums/mod/journal/journal.asp?jn=339729 Ignore the growing Jesus controversy.

Cool. That's actually a really good example of a domain specific language. I personally would've gone for a dictionary using functions as the values instead of raw code, though. Have you considered writing your MUD in python, or some other higher level language (like lisp)? You could probably save yourself a lot of time by using their dynamic evaluation feature, especially since MUDs don't strike me as the most performance-intensive applications.

Share this post


Link to post
Share on other sites
No, they aren't very performance intensive. But they don't usually run on the fastest machines available either. Unlike most other online games, there isn't any processing that can be shunted off to clients (Since the client program is TELNET). And you'd be surprised how slow text processing can get.

Share this post


Link to post
Share on other sites
I've been reading this thread a thew times over and there appears to be some confusion/misconception here, bytecoder is referring to domain specific embedded languages (DSELs) not DSLs though very closely related each have there own advantages/disadvantages. DSLs can be written in virtually any programming language but only a hand few of languages can be used to write DSELs.

DSELs overcome some of the limitations of DSLs. Typically DSELs are little languages that come in library form in some host general purpose language like in lisp, haskell, Nemerle, even C++.

Quote:
Original post by bytecoder
and I'm wondering what are the benifits of them over, say, data structures/classes?


The fact that code becomes declarative rather than imperative, you describe what needs to be done rather than prescribe how it should be done.

This raises the level of abstraction & expressiveness to a significantly higher level, one that typically matches are mental model.

Things like data structures, classes, etc are typically generated from a DSEL. The code generated is all laborious, repetitive boilerplate code that you should generally not do by hand.

Quote:
Original post by bytecoder
I really do want to know the advantages of DSLs.


First i'll say the advantages/disadvantages of DSLs then i'll say the extra advantages of DSELs they typically overcome some limitations of DSLs.

DSL advantages

  • Declarative programming model, describe the whats rather than prescribe hows.


  • virtually eliminates all repetitive boilerplate code.


  • Code that matches are mental model.


  • Embodies domain knowledge and typically domain specific optimizations.


  • Significantly higher level abstraction & expressivity


  • Rapid Development for the users of the DSL


  • Easily support many general-purpose programming languages.



DSL disadvantages:


  • Typically high learning curve since the user has to learn the syntax and maybe more


  • Generally Poor interoperability with other DSLs


  • Generally a DSL does not understand the structure of other languages it may embed, makes it harder to debug.


  • High development cost, they may take time to build & debug.


  • Can have many translation phases.


  • Needs new tools, new IDE or IDE pluggin etc



DSEL advantages (subsumes most of DSL advantages)

  • Lower learning curve, client typically already knows the language


  • Typically Lower development costs.


  • Excellent interoperability with other DSELs, it's trivial to use different libraries together therefor it's trivial to use different DSELs together.


  • Self documenting code.


  • Programming Idiom enabling, want support for the logic paradigm in the host? or want to support "Design by Contract" simple write it as DSEL.


  • Some cases it's possible to extend the syntax to the host language, like in Scheme, Nemerle, Boo.


  • Concise and easy to write code.


  • Typically extendable.


  • No need for a new tools, IDEs or IDE pluggins, just use the same tools for the host language.


  • Extra translation phases eliminated.



DESL disadvantages:

  • Poor cross language support.


  • Typically longer build times although this is insignificant compared to the expressiveness gained.


  • Some people go to far with it and abuse the host language.

Share this post


Link to post
Share on other sites

This topic is 4373 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this