Arc Forumnew | comments | leaders | submitlogin

Yes, I mean exactly something like this :)
2 points by akkartik 4396 days ago | link | parent | on: Bug in cut

Yeah, none of those call sites seem responsible, as far as I can see. The calls in markdown and unmarkdown only trigger if the string starts with certain chars, which it doesn't. Remind me, are you using anarki?

Ohh, did you mean bindings for http://download.plt-scheme.org/doc/html/reference/Command-Li...?

Ok, try it now:

  anarki $ git pull  # should now have a file called 'arc'
Now an executable file like this (called say x.arc) works:

  #!/PATH/TO/arc
  (prn argv)  ; argv now contains commandline args
Try it out:

  anarki $ ./x.arc a b c
  (./x.arc a b c)
The repo is a little messy now. I had to create a new asv.scm that looks substantially like as.scm, and the 'arc' script is in addition to the older 'arc.sh' which is for interactive use (and which I don't use, preferring to directly 'racket -f as.scm'). Anybody have suggestions for either? Should we rename the old arc.sh to 'iarc'?

I'm still trying to get the solution to work, but the last time this came up was http://arclanguage.org/item?id=10344.
2 points by akkartik 4399 days ago | link | parent | on: Problem with auto-uniqs

Agreed. Which is why we should pool resources and share the first time we encounter such a bug. Or even a possible such bug that we can then debug together.

For my part, I have had an eye out for it for three years and have yet to encounter such a bug. Here's my hand-wavy reasoning for why I think it can't happen: for it to happen, an outer macro would have to rely on a use of a specific gensym inside a nested macro. I can't imagine how that could happen short of actually trying to use a gensym:

  (macro1
    (macro1
      ..x23..))  ; brittlely relying on the gensym turning into *x23*
And if we are to worry about this we can worry about all gensyms anyway.
2 points by malisper 4399 days ago | link | parent | on: Problem with auto-uniqs

Okay, so the example with accum actually does work fine, but, only due to lexical scoping. I'm still afraid of the possibility of macros using the same symbols and causing a collision. While it looks like it would be an extremely rare bug to find, it would be one of those bugs that are a real pain to debug.

Anarki doesn't have mailgun support yet. It will reset passwords if your server supports sending email using the local unix sendmail command. So I can think of two options:

a) Does mailgun provide a sendmail command that you can download? If so, just installing that might be all you need.

b) Anarki has rudimentary support for GET and POST on arbitrary urls.

  arc> (get-url "http://google.com")
  ("<HTML><HEAD><meta http-equiv=\"content-type\" content=\"text/html;charset=utf-8\"><TITLE>301 Moved</TITLE></HEAD><BODY><H1>301 Moved</H1>The document has moved<A HREF=\"http://www.google.com/\">here</A>.</BODY></HTML>")
Can you try to figure out the right URL to put into the get-url call or similar post-url call? They're implemented in lib/web.arc, and feel free to ask us questions to help get you on your way.
2 points by akkartik 4399 days ago | link | parent | on: Problem with auto-uniqs

Yeah, I actually thought about this use case back when I wrote accum for wart. But there's no problem here since the two expansions also create lexical scopes. In unmodified anarki:

  arc> (mac foo (accfn . body)
         `(withs (acc@ nil ,accfn [push _ acc@])
            ,@body
            (rev acc@)))
  #(tagged mac #<procedure: foo>)
  arc> (foo a
         (each l '(1 2 3)
           (a:foo b
             (each m (list l (+ l 1) (+ l 2))
               b.m))))
  ((1 2 3) (2 3 4) (3 4 5))
Is there some other scenario that I'm not considering?

(I hadn't realized that w/uniq is superior to implicit gensyms in this regard. Thanks.)

2 points by malisper 4400 days ago | link | parent | on: Problem with auto-uniqs

The idea behind autouniqs is that they remove some boilerplate code (ie w/uniq). The current implementation of autouniqs[0] is actually broken. The problem boils down to the fact that with the current implementation, macros will wind up using the same uniqs every time they are expanded. Say accum was implemented using autouniqs.

  (mac accum (accfn . body)
    `(withs (acc@ nil ,accfn [push _ acc@])
       ,@body
       (rev acc@)))
The intention is acc@ will be replaced with a uniq every time accum is expanded. With the current implementation of autouniqs, acc@ will be replaced with a single uniq in accum's definition. This leads to problems with nested use of accum.

  (accum a
    (accum b
      (...)))
What clojure does to solve the problem is combine "autogensyms" with its implementation of backquote. All the symbols ending in '#' inside of the same backquote are replaced with gensyms when the backquote is evaluated. While clojure's implementation is good for most things, it breaks down with any kind of nested backquotes [including `(... ,(... `(...)))] since the autogensyms will not be the same inside all of the backquotes. I think tying the autogensyms to backquote is a requirement due to the fact that every time the backquote is evaluated new gensyms would have to be put in to replace all of the autouniqs/gensyms (feel free to prove me wrong). This becomes obvious when one starts thinking about macros with nested backquotes and how they would expand. What I want is some version of autouniqs such that they completely eliminate the need for w/uniq.

[0] http://www.arclanguage.org/item?id=18235

1 point by akkartik 4400 days ago | link | parent | on: Problem with auto-uniqs

Hmm, I've never seen this idea before and haven't seen any system supporting it. Does clojure?

Can you give an example where it's useful?

2 points by malisper 4400 days ago | link | parent | on: Problem with auto-uniqs

I may have figured out a possible way to implement backquoting in such a way based off of Steele's implementation[0]. All that is needed is an addition macro that will be put outside of each backquote expansion. When that macro finally is expanded (when all of the other backquotes have been used up), it would go through and replace all of the specified symbols with a uniq symbol up to any further backquotes. This would make it possible to have the uniqs generated every time each backquote is executed.

The only problem I can think of is something like this:

  `(x@ `(x@))
How would one specify for the generated symbols for both x@ to be the same. There might already be a way to do it through use of unquoting but I'm not sure how that would interact with the backquote implementation.

[0] http://www.cs.cmu.edu/Groups/AI/html/cltl/clm/node367.html#S...

2 points by rocketnia 4400 days ago | link | parent | on: A tiny lisp interpreter in JS

If you want to have full tail recursion elimination, I recommend changing everything to work in continuation-passing style. That will overflow the JS stack even sooner, so I recommend using a trampoline.

  // before
  function plus( a, b ) {
      return a + b;
  }
  
  // after
  function plus( a, b, then ) {
      // We call `then()` only after we've unwound the stack.
      return trampolineBounce( function () {
          return then( a + b );
      } );
  }
  
  // the trampoline system
  function trampolineBounce( func ) {
      return { type: "bounce", func: func };
  }
  function runTrampoline( func ) {
      var step = func( function ( result ) {
          return { type: "result", result: result };
      } );
      while ( step.type === "bounce" )
          step = step.func();
      return step.result;
  }
  
  // example usage
  var onePlusTwoPlusThree = runTrampoline( function ( then ) {
      return plus( 1, 2, function ( onePlusTwo ) {
          return plus( onePlusTwo, 3, function ( result ) {
              return then( result );
          } );
      } );
  } );
This part is a bit redundant:

  function ( result ) {
      return then( result );
  }
It's equivalent to `then` but uses one more JS stack frame. We can just reuse the `then` continuation directly. In general, the places we can do this are tail calls.

  // example usage with a tail call
  var onePlusTwoPlusThree = runTrampoline( function ( then ) {
      return plus( 1, 2, function ( onePlusTwo ) {
          return plus( onePlusTwo, 3, then );
      } );
  } );
---

"I'm finding a method to transform recursion code to iteration code automatically"

I don't think it's possible to get full tail recursion elimination that way unless you statically analyze the whole program, or you transform the code so it uses the CPS-and-trampolining technique above.

Maybe you can get something somewhat less powerful than full tail recursion, but I don't have advice on that. If you do want to work on that, here's an example of a tail-recursive while loop you can test with:

  ; Evaluate an expression repeatedly until it returns something falsy.
  ( (lambda (f body) (f f body))
    (lambda (f body)
      (if (body)
        (f f body)
        #f))
    (lambda () ___))  ; insert expression here
2 points by kraks 4400 days ago | link | parent | on: A tiny lisp interpreter in JS

Thanks to your advices. The runtime is based on Node.js, so there is no tail recursion elimination, I'm finding a method to transform recursion code to iteration code automatically, do you have some advice?

Thx,i have almost done my arc site,but when a user forgot his password and he need to reset by email,but cannot get the email...i wanna know how to add email feature in arc site? by the way,i use mailgun.com to send and they give me HTTP API.like this http://documentation.mailgun.com/quickstart.html#sending-mes...

I'm ambivalent about the feature as well, but you should be able to double @'s to insert a literal @. In anarki:

  arc> "abc@@example.com"
  "abc@example.com"

Yes, posting here is best. Sorry I think I missed one of your emails? Was out of town for a while.

hi,shader:i have a new problem with arc,but i donot know how to contact u...is it ok to post Q here?

Yeah, atstrings is a pretty awkward feature. It is possible to opt in and out of it, but only at the top level:

  (declare 'atstrings t)
  (declare 'atstrings nil)
This affects how strings are processed by 'ac. That is, it only matters for compilation/macroexpansion phases.

I see some of Anarki's tests set 'atstrings to a particular value as they go along, but then they don't reset it. This might be why you see some tests working when yours don't.

(In Anarki, the declarations* global table holds these values, so it's technically possible to save and restore the old value by reading that table.)

---

The REPL behavior you observed is confusing in a different way than you thought. It treated your input as a malformed command, three well-formed commands you didn't know you were entering, and finally an unfinished string literal:

  "abc\@
  
  example.com
  
  "
  "
  
  abc@@example.com
  
  "
This is where the "\n" response came from, and it's why you received multiple responses per input line.
3 points by lark 4401 days ago | link | parent | on: Bug in cut

I'm unable to reproduce it now. I disabled the bug fix, and I believe I am now running the same code as I did when the bug occurred, but I no longer get this exception when I visit that url (it's an ordinary GET request without parameters). The state of the app has also changed and I wonder if this state change has something to do with it.

What's certain is that it's a call that passes 3 arguments to cut. I had logged the exact call to cut to be:

  (cut "U2FsdGVkX19jl4f9tgc8cwsQso1Q1HMYtqzp4HAQO+3fL9LTcN5X7UEZTaz7V+F2" 128 64)
It might be one of:

  app.arc:markdown
  app.arc:unmarkdown
It can't be arc.arc:split because either the first parameter is a hardcoded 0 or the call takes only 2 parameters.

It can't be arc.arc:ellipsize because the call uses a hardcoded 0.

It can't be app.arc:shash because the second parameter there is a hardcoded 0.

It can't be app.arc:urldecode because the 2nd and 3rd parameters there should differ by 2 and they instead differed by -192 (did I get this right?)

It can't be strings.arc:lines because calling (lines "U2FsdGVkX19jl4f9tgc8cwsQso1Q1HMYtqzp4HAQO+3fL9LTcN5X7UEZTaz7V+F2") doesn't cause this error.

It probably isn't strings.arc:trim because calling (trim "U2FsdGVkX19jl4f9tgc8cwsQso1Q1HMYtqzp4HAQO+3fL9LTcN5X7UEZTaz7V+F") doesn't trigger it either.

It can't be app.arc:paras because I'm not using paras anywhere.

It can't be strings.arc:slices because I'm not using slices anywhere.

It can't be html.arc:hex>color because the values there are hardcoded.

It can't be html.arc:shortlink because it uses only 2 parameters.

3 points by rocketnia 4401 days ago | link | parent | on: Bug in cut

When you got the error in the Arc server, what was cut's caller? Maybe it's buggy in its own right, and fixing it might make this change irrelevant.

I've seen cut-like behavior that uses out-of-order endpoints to reverse the list. Groovy does this for instance:

  >>> ​[ 1, 3, 5, 7, 9 ][ 3..1 ]​
  [7, 5, 3]
(http://groovyconsole.appspot.com/)

If we want this kind of behavior for Arc's 'cut (and I'm not saying we do), then your change is inconsistent with it.

2 points by rocketnia 4402 days ago | link | parent | on: A tiny lisp interpreter in JS

The parser implementation is pretty concise. :)

I'm concerned about looping. It looks like you're implementing function calls in terms of JavaScript function calls, so there's no tail call elimination, and a recursive loop will soon exhaust the JS stack. A while loop could be a practical alternative.

3 points by rocketnia 4407 days ago | link | parent | on: A Javascript parser in Arc?

I recommend using the UglifyJS JavaScript parser, which exposes a well-documented AST: http://lisperator.net/uglifyjs/ast

---

"It's the kind of takeover any language could do to any other"

JavaScript's a big language. It comes standard with complex (and I'd say quirky) systems for floating point numbers, date handling, and regexes. ECMAScript 5's strict mode repurposes the same JavaScript syntaxes for slightly different semantics, fracturing the language even within the same spec. That spec also defines at least three different ways of interpreting a JS string as JS code, if we count eval(), strict mode eval(), and the Function() constructor.

The standard is just one small glimpse of the landscape of JavaScript compatibility:

The language is commonly split into intentionally different dialects. The HTML spec willfully violates the ECMAScript spec so that document.all can be falsy[1]. Mozilla's asm.js repurposes the same JavaScript syntaxes to have substantially different performance when they're used a certain way. And of course there are proper extensions and variations of the language, like TypeScript, Harmony, Mozilla's own line of JavaScript versions, the JavaScript-inspired UnityScript and ActionScript, etc.

Nonstandard features are frequently needed. Different JavaScript platforms like the HTML spec, Node.js, Rhino, RingoJS, and Windows Script Host add (or don't add) their own varying tools for concurrency, sandboxing, error handling, debugging, global scope management, package distribution, and module imports, which tempts even general-purpose library writers to stray from standards. Meanwhile, JavaScript libraries sometimes silently take advantage of widespread but underspecified features such as function names, function toString() representations, object.__proto__, and object key iteration order.

Given all this, the good news is that a translator from JavaScript can't be expected to have 100% compatibility. Like Caja, the Clojure Compiler, and Browserify, it may have to put quirky limits on the subset of JS code it intuitively supports. One place to look for a not-so-quirky subset might be lambdaJS[2], which has been used for formal correctness checking.

[1] http://stackoverflow.com/questions/10350142/why-is-document-...

[2] http://blog.brownplt.org/2012/06/04/lambdajs-coq.html


In case anyone wonders what's wrong with (if ...), I've put together a demonstration of translating Arc-like code into the flavor of generalized arrows[4] David and I use for implementing this stuff:

  (if foo
    (bar baz)
    qux)
  
  
     (  |         +   |       )        |   |   |
     ( foo(true)  +  foo(nil) )       bar baz qux
  =======================Disjoin=====================
  foo(true) bar  baz  qux   +   foo(nil) bar baz qux
   |         |    |    |    +    |        |   |   |
  Drop      Drop Drop  |    +   Drop     =Apply= Drop
                       |    +               |
                       =========Merge========
                                  |
In this graph, sum types (A + B) are edges separated by + and product types (A * B) are simply juxtaposed edges. I've labeled the edges around Disjoin to show which signals go where.

The "Disjoin" operation is the distributive law on product and sum types, taking ((A + B) * C) to ((A * C) + (B * C)). In simple cases, it has to synchronize C with a combination of A and B so it knows which output to send C's packets down.

The "Merge" operation takes (A + A) to A, forgetting which branch it was on. In simple cases, it has to synchronize the original two signals becuase the output should only be inactive when both inputs are inactive. If we're using dynamic typing, we may also need to check the inputs dynamically to make sure their periods of activity don't overlap.

Overall, one call to (if ...) causes multiple synchronization points in the code.

You might wonder what Arc could use here if not (if ...), and my guess is it could use a structured data type with associated special forms that can be implemented with implicit concurrency:

  (def left (x) (annotate 'left x))
  (def right (x) (annotate 'right x))
  
  ; Sum types distribute over product types.
  ; ((A + B) * C) -> ((A * C) + (B * C))
  (disjoin (left a) c)   -->  (left (list a c))
  (disjoin (right b) c)  -->  (right (list b c))
  (disjoin other c)      -->  (err "Can't disjoin")
  
  ; Sum types are commutative.
  ; (A + B) -> (B + A)
  (mirror (left a))   -->  (right a)
  (mirror (right b))  -->  (left b)
  (mirror other)      -->  (err "Can't mirror")
  
  ; Sum types are associative.
  ; ((A + B) + C) -> (A + (B + C))
  (assocsl (left (left a)))    --> (left a)
  (assocsl (left (right b)))   --> (right (left b))
  (assocsl (right c))          --> (right (right c))
  (assocsl other)              --> (err "Can't assocsl")
  ; (A + (B + C)) -> ((A + B) + C)
  (assocsr (left a))           --> (left (left a))
  (assocsr (right (left b)))   --> (left (right b))
  (assocsr (right (right c)))  --> (right c)
  (assocsr other)              --> (err "Can't assocsr")
  
  ; (A + A) -> A
  (merge (left a))   -->  a
  (merge (right a))  -->  a
  (merge other)      -->  (err "Can't merge")
  
  ; (A -> C) -> (B -> D) -> ((A + B) -> (C + D))
  ((lift-sum l r) (left a))   -->  (left (l a))
  ((lift-sum l r) (right b))  -->  (right (r b))
  ((lift-sum l r) other)      -->  (err "Can't lift-sum")
This is quite a bundle of special forms to add, and I'm probably forgetting a few. I'm not exactly sure how to implement them, especially considering they would have to deal with Arc's arbitrary recursion. ^_^;

[4] http://www.megacz.com/berkeley/garrows/


Good questions! I keep wanting to tie this stuff back to Arc somehow, so that people here can care, lol, but it's hard to see where to start.

I'll assume we're talking about something like RDP, but not quite RDP. David Barbour's goals for RDP include safe distributed programming, secure mashups, and sometimes even type-directed reduction of boilerplate. Thus RDP isn't necessarily RDP without an appropriate static type system, and we proabably don't need to commit to that part here.

Let's just call what we're talking about "continuous reactive" code, or "continuous" for short. :)

I'll answer out of order a bit.

---

"And what kind of metaprogramming models besides function/macro/fexpr do you see working on top of such a system?"

All of these actually keep making sense in a continuous system. The only things that can't technically be carried over are certain kinds of side effects.

Here's a more complete description of the differences:

- Most imperative side effects don't make sense. If (do (= x 1) (= x 0)) is executed continuously at every instant, then at no time is x just 1 or just 0. Continuous reactive programming needs its own particular side effects to deal with continuously displaying things, continuously maintaining connections to things, continuously monitoring the current state of the mouse, etc. Instead of mutation, continuous reactive code can use demand monitors, which aggregate sets of values. Similarly, we would have to avoid effects related to first-class continuations, threads, etc., unless we can make sense of them.

- Since all the effects at a given instant are simultaneous, the data/control flow doesn't need to be processed in a particular order, and it can naturally be concurrent, which in turn means each concurrent part can be undisturbed for a good period of time without needing to be recomputed. This means certain constructs like (if ...) stick out as expensive operations, since they must synchronize their inputs and outputs rather than letting them pass through concurrently.

- Eval and function calls are pretty weird operations. In a continuous program, the entire data flow graph exists like a constantly marching trail of ants, sometimes switching between different conditional branches. I think a dynamic call causes that trail of ants to sometimes snap between different iterations of a fractal pattern. My current implementation[1] supports "functions" but doesn't support arbitrary recursion, because I keep every possible trail instantiated regardless of whether it's currently in use. It's like all the functions are inlined whether we like it or not. (I actually kinda like it.)

- If we care about secure mashups, passing a big context object around tends to be a bad idea, especially if it's implicit. Fexprs may need a redesign in order to avoid passing authority to code that doesn't need it.

---

"How would you build a declarative continuous state system on top of arc? Or would it be better to start from scratch?"

(Building the execution semantics is probably a bigger challenge than building the state resources, so I'll assume that's what you mean.)

While starting from scratch would keep things simpler, I don't think it's necessary, as long as there's some bridge to manage the continuous side from the procedural side and/or vice versa. A single language could have dedicated syntaxes (e.g. lisp special forms) both for procedural code and for continuous code.

I've actually been thinking about how a single (fn ...) syntax could be used for both. Pure code is a special case of error-free continuous impure code, and that in turn is a special case of error-free procedural code, so a single abstraction might cover it all.

However, dynamic errors make things more interesting. In procedural Arc code, (do (foo) (err "oops 1") (bar) (err "oops 2")) would not execute (bar) because that comes after an error has occurred. In continuous code, all of the code is executed at every instant, so there is no "after" to speak of, and (bar) executes at the same time as both errors occur. (Actually, David's approach would be to terminate the computation as soon as possible and try to roll back any effects that have occurred in the meantime, so in that case (bar) would not usually be seen to execute.)

This is enough of a jarring discrepancy that I've tabled the idea of unifying the (fn ...) syntax in the procedural language I'm working on.[2] I think it's something that can be done, but it's more complex than I first thought.

Anyway, suppose we have two different syntaxes, or suppose (as David prefers) we don't have a continuous (fn ...) syntax at all but instead use concatentive programming techniques.[3]

Either way, it's painful to bridging between one style of computation and another.

Procedural code managing continuous code: Procedural code has to deal with continuous signal input similarly to how it would traditionally deal with keyboard and mouse input, and it has to deal with continuous signal output kind of like drawing to a canvas. This means writing 2-5 imperative code blocks for every bridge, at least until some common bridge patterns can be abstracted away.

Continuous code managing procedural code: One way to use continuous code to trigger an imperative action would be to build a continuously updating collection of the imperative actions we want performed, annotating each one with a timestamp so it's clear when it's supposed to happen exactly. This is cumbersome enough that I haven't tried it yet, but it's basically the kind of FFI layer that a continuous-only language would need in order to play nicely with existing OSes and protocols.

The Web is a good example of a system that already has bridges like what we'd need. An HTML document can have continuously existing tags and attributes that cause JavaScript code to be executed at certain times. In turn, JavaScript code can insert and remove declarative HTML and CSS as it goes along.

Sorry for using so many JS metaphors. :) Aside from Rainbow's UI experiments, I don't know of any Arc applications which continuously monitor or display something.

---

[1] Underreact: https://github.com/rocketnia/underreact

[2] Penknife, which currently is hidden away inside Era and not described in the readme: https://github.com/rocketnia/era

[3] Either way, I've pretty much made this in JavaScript already,[1] but my (fn ...) syntax is a bit cumbersome because I'm using strings for variable identifiers, and my concatenative syntax is even more cumbersome because it has to pass around explicit first-class type annotations with no type inference. I think there's room to improve on this, especially in something like Arc that has macros.


How would you build a declarative continuous state system on top of arc? Or would it be better to start from scratch?

And what kind of metaprogramming models besides function/macro/fexpr do you see working on top of such a system?

It seems like it could either be a really 'alien' programming model that requires very different approaches, or a simple set of wrappers on top of existing models. I don't know enough about it yet.


It actually surprises me how much Versu development resembles some of my own thoughts about organizing large-scale interactive story plots. I once dreamed of making a language for building interacting FSMs, with support for automatic testing or formal model-checking to find dead code. Apparently this was all in the scope of Praxis and Prompter tools, and I didn't have to lift a finger to see this dream come true. ;)

I'm concerned about some drawbacks this project might face, having to do with the use of instantaneous events for modeling story actions and the use of inline dialogue generation.

Instantaneous events are something I tend to see as a misfeature[1]. The notion of a discrete timeline is baked into the sequence-of-paragraphs UI, the screenplay-like Prompter language, the state machines, and the visualization graphs. Even the logical framework needs it, since the characters instantaneously "remove" past beliefs as they're convinced of incompatible beliefs to replace them.

At least it can be said that in Versu's chosen problem domain, events are essential. They couldn't be "fixed" without changing basically the entire story UI, the tools, and the formalism, leading to a completely different product. At least this project seems to have good tooling to tackle many event-related issues head-on.

As for inline dialogue generation, I've just never been comfortable with the thought of generating story prose using string concatenation; at least a more structured format would be nice. Emily Short and Graham Nelson are two of the people who think about this topic quite a lot, and their context-sensitive text macro approach is impressive, but it uses too much stateful magic for me to want to dive in and use it. (Same with some of the naturalistic syntax...) It's not like I dive into story-writing regardless, but it's one of the basic motivations I use to write programs, which is why I have opinions like this one. :-p

Regardless of any drawbacks--even if Versu had been a closed system under Linden Labs--I was always eager to use it. I may not write full stories, but I do design lots of original characters and settings, and Versu has been designed with the high-level idea that characters can be swapped out for each other to see how they interact in different circumstances. It could be just the right platform to give some life to my ideas.

[1] http://awelonblue.wordpress.com/2012/07/01/why-not-events/


Versu is an interactive story platform that was developed in a project overseen by Linden Labs, best known for Second Life. The drivers behind this project were Emily Short, a famous author of text-based interactive fiction, and Richard Evans, who had previously worked on the AI for The Sims 3. These are some documents describing the platform they built.

I think one of the docs people here would like is "Prompter: A Domain-Specific Language for Versu":

https://versublog.files.wordpress.com/2014/05/graham_versu.p...

Graham Nelson made Inform 7, an interactive fiction engine with English-like syntax. Now he's made Prompter, a similarly naturalistic language for Versu. In that introduction to Prompter, he talks about motivations and principles for DSL design.

Prompter compiles to Praxis, which is a logic programming language Richard Evans designed for Versu to handle characters' reasoning, decision-making, emotions, manners, etc. The core of the formal approach is described in "Computer Models of Constitutive Social Practice":

https://versublog.files.wordpress.com/2014/05/ptai_evans.pdf

I haven't had a chance to read "The AI Architecture of Versu" yet, but seems to describe the practical details of the development tools for Versu, focusing around Praxis:

https://versublog.files.wordpress.com/2014/05/versu.pdf

I expect almost anything that makes sense for Versu AI authoring will probably be possible to achieve in Praxis thanks to its highly logic-influenced design, and that the most frequently needed things will be ergonomic for writers thanks to Prompter.

I'm not sure how much these tools are public yet, and actual playable Versu stories have only been built for iOS, but it'll be nice to see this improve. Linden Labs had actually shut down the Versu project earlier this year, and this version of the Versu website was just opened up this week, so the project seems to be in a trajectory toward more openness.


It should be supported now! https://github.com/smihica/arc-js/commit/7919d4654cc1ce9c701...

As a guess you might need to use js char literals like ' ', '\n', etc. Can you try that?
More