MISC: An experimental LISP-like language

MISC started when I got sick of XML's lack of consistent structure and it's heavy markup. I wanted something consistent, clean and executable like LISP but with a more general basic data structure. This was the initial spark "LISP with maps instead of lists".

  • [if [ 5 10] then:[+ 5 10] else:[- 5 10]]
  • [let '[square:[lambda '[x:1] '[* x x]]]
      '[square 12]
    ]

  • [take 20 [numbers from:0]]

The result is not a language for real-world use but one that I hope embodies many different unique and novel design decisions in a way that triggers thoughts and ideas in those that take the time to play with it. I've written up some of my experiences of designing the language and a fair bit of documentation. It also runs as an applet with some neat inline documentation.



What's different or why you should be interested:

  • Novel LISP-like language
  • Homoiconicity (ie. source code that is data) using maps
  • A great lazy data-language
  • Cool stuff with metadata
  • A metacircular– interpreter and syntax-colourer

Find out a bit more about MISC, and run it directly in an applet.
(NB. All the examples are clickable and use alt-return to execute code)

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.

Impressive :-)

Impressive :-)

I like your work, applet suggestions

Nice web site. I like MISC, a pity the applet outputs only NULL on error.

When you evaluate an example in the applet, that can affect the next evaluation. For example, on page 18:

=> [mapm '[1 2 3 4 5] [lambda '[v:1] '{v [+ v 1]}]]
`['[1 2] '[2 3] '[3 4] '[4 5] '[5 6]]
=> [[partial-app * fix:'[2:2] rename:{}] 12]
24
=> [[partial-app / fix:'[1:1] rename:{2:1}] 12]
`[@Apply @Divide `[1:1 12 0:@Substitution] `[true:true false:false null:nil +:@Add
 -:@Subtract *:@Times /:@Divide %:@Remainder if:@If =:@Equals <:@LessThan map?:@IsMap
 lambda?:@IsFunction number?:@IsNumber string?:@IsString null?:@IsNull map:@MapTo
 keys:@Keys get:@Get contains?:@Contains union:@Union append:@Lambda string+:
@Substitution meta:@Meta [snip]

It would be nice if built-ins like + and * would take any number of arguments without the help of foldm. When I do

getdoc take

The result is

@Lambda

That does not seem very useful, would you consider giving the result of [getdoc take] instead? (ie top-level brackets optional)

Thanks!

Thanks!

Reporting errors is one of MISC's main failings at the moment. At the moment I can output a ton of junk or null, I choose null for the applet.

The example you quoted of the applet failing was actually a race condition in the applet drawing and printing code. I've fixed it now - thanks. The actual interpreter contains no state at-all which is maybe taking purity too far.

Agreed about + and *; I had never thought of allowing the top-level brackets to be optional, it's an interesting idea.

Fixed

The example you quoted of the applet failing was actually a race condition in the applet drawing and printing code. I've fixed it now - thanks. The actual interpreter contains no state at-all which is maybe taking purity too far.

Seems to be fixed. The Environment is a form of state, no?
IMHO impurity is only required when dealing with a (shared) resource, and then you may want a special treatment to control the access etc.

Agreed about + and *; I had never thought of allowing the top-level brackets to be optional, it's an interesting idea.

Downside is that it will start looking like TCL ;)

What I meant was that the

What I meant was that the interpreter, between evaluations, holds no state. You cannot define a function in the root environment, without putting it in the bootstrap file.

I really like purity (especially thinking of MISC as a possible data language) but I am quite tempted to develop an impure version of MISC based on Lua's VM that also ties into ObjC as a scripting language. ;) I've found it hard to write an efficient pure + lazy language and MISC is really slow. Perhaps a pure mostly eager language would be easier.

curious about the major issues

I like it.

"I changed the basic structure several times to fix major issues I hadn’t thought of"

I'd be curious to hear what these were.

Just briefly off the top of

Just briefly off the top of my head, roughly in order:
  • Initially:
    • Lisp with maps. [if [= 2 3] then:[+ 3 4] else:[+ 5 6]]
    • Eager evaluation -- metadata and args quoted if not immediately run
    • No separate metadata [+ 3 5 author:"will"]
    • Implicit letrec everywhere -- [* m [+ m n n:10] m:20]
  • Switched to lazy evaluation -- causing many many complications, but fixing some of the quoting problems
  • Changed to separate metadata -- [+ 3 5]@[author:"will"]
  • Switched to explicit let/letrec -- [let [n:20] [* n 2]]
  • Made union lazy allowing generating 'infinite' maps
  • Removed hacked special forms like if, let, lambda -- [let '[n:20] '[* n 2]]
  • Solved handling of data quoting levels -- '[a:4 b:,[+ 2 3] c:'[6 7 ,,[* 2 4]]]
There are probably a few more, I spent a long time designing around different issues. There was also a fair bit of interaction between all the above mentioned design decisions which complicated things further. Probably getting the way it handles data right as multiple levels took the longest. Also designing a lazy language was very tricky to get right, there were all sorts of subtle evaluation bugs for a long time.

Very interesting

I've been developing a language based pretty much on the same initial idea as MISC, namely using map as the ultimate data structure for both code and data. After that, there is some serious divergence.

I'd say the first difference is in quoting. My language, GENS, did not have any quoting/unquoting mechanism: a map is quoted iff it's in head-normal form, otherwise it gets reduced. Any map of form (in your notation) [a a:b] could be reduced to [b a:b]. I guess this feature would be what you refer to as "implicit letrec" in one of your replies. I'd be interested to hear why you dropped it?