Arc Forumnew | comments | leaders | submitlogin
Any interest in Arc on the iOS Obj-C runtime?
3 points by arthurrr 4150 days ago | 16 comments
So is there any interest in an Arc variant that runs on the iOS Obj-C runtime? I am curious to know if there is interest in this kind of thing.

It's not exactly the same, but it follows the definition of Arc as it's defined in the tutorial text file (for the most part). However I did change a few things that I didn't like :)

This is just something I've been playing with the past few months. I currently have a web interface to the Obj-C runtime on the iOS device, which is like having a REPL. I also have simple bindings for ImageMagick, cURL, PCRE, and CoreGraphics. Next on the list is CoreText.

Longer term goal is to be able to implement the functionality necessary make the web browser, HTML, CSS, and JavaScript irrelevant.

So let me know and I will try and write some documentation and make a release.



3 points by thaddeus 4150 days ago | link

Am I interested? ... For sure.

I've used a clojure->scheme->c[1] a little, but Arc could also have it's place too.

Actually I had always wondered if, or hoped that, someone would build Arc atop gambit scheme instead of racket which, in my mind, would be the easiest path to also get Arc working on iOS, but it's not my area so maybe you can tell me which would be better.

Either way I think Arc would be a great fit for creating iOS apps as Arc has much simpler language constructs and mutability/concurrency wouldn't be as big of an issue given the localized nature of mobile code.

[1] https://github.com/takeoutweight/clojure-scheme

-----

1 point by rocketnia 4144 days ago | link

"Either way I think Arc would be a great fit for creating iOS apps as Arc has much simpler language constructs and mutability/concurrency wouldn't be as big of an issue given the localized nature of mobile code."

Sorry, I think I'm not catching all the context of this sentence. What language's "language constructs" are you comparing with Arc's? (Objective-C? Gambit Scheme? Racket?) What environment with "mutability/concurrency" issues are you contrasting with "mobile code"? (Server programming?)

I've only barely done any iOS programming, but I've done a bit of work on Android apps, and Android organizes rendering and event handling onto different threads.

-----

2 points by thaddeus 4144 days ago | link

Arc has fewer data types and consequently there are less methods/means required to interact with them. For example clojure has at least a dozen collection types (sets, various types of maps, vectors, seqs, lists, cons, etc, etc...) while at the same time having a variety of methods used to access them (atoms, refs etc).

This variety creates depth to the language, but it also makes the language more complex (even if appropriate). For example even the terms overlap creating confusion... I.e what's an 'atom' ? what's a 'map'? ifn? vs fn?, why does a vector get treated as a function?

So each of these "constructs" serve a purpose, some of which are to deal with state and time, or shall I say concurrency and mutability which often have to do with parallel computing or managing concurrent threads which all operate on the same object or data structure.

Currently Arc is limited to a very small set of data structures and methods to interact with. I believe arc still deals in mutability only, relying heavily on queues to manage state and time. Either way Arcs minimal set of constructs are probably well suited for many mobile code applications given you only need to manage interaction from a single user.

-----

2 points by jsgrahamus 4150 days ago | link

And Gambit has been ported to iOS and Android.

-----

1 point by akkartik 4150 days ago | link

With regard to your trailing-paren hack at http://subjectivelisp.org/index.php?title=How_code_is_organi... -- I'm curious to get your reaction to my toy interpreter: http://github.com/akkartik/wart/blob/190ced3d73/004optional_...

-----

2 points by Pauan 4149 days ago | link

Second shameless plug: I've changed Nulan significantly since I last showed it off here. Here's a page describing Nulan's syntax system, which I believe is superior to all existing Lisp syntax systems:

https://github.com/Pauan/nulan/blob/79ea2a9fee8cb1ea7640d8f5...

-----

1 point by akkartik 4149 days ago | link

Very cool!

If I follow everything on that page, this allows you to programmatically control where lists are segmented, and to generalize infix, resolving function/macro calls to be anywhere in the list. In other words, macro foo doesn't have to look like

  (foo ...)
it can also look like

  (... foo ...)
Does this make the grammar context-sensitive? Does it often introduce ambiguity? Have you run into non-terminating parsing? Can you talk about how it compares with oMeta? (Are you sure you aren't greenspunning it? :)

-----

2 points by Pauan 4149 days ago | link

"If I follow everything on that page, this allows you to programmatically control where lists are segmented [...]"

Something like that, yes.

---

"[...] resolving function/macro calls to be anywhere in the list. In other words, macro foo doesn't have to look like"

Not quite. The parser is very simple: it just pushes symbols around. Which means that when you use a syntax rule like this:

  $syntax-infix "foo"
Then the parser will rewrite this:

  1 foo 2
Into this:

  foo 1 2
This all happens before macros are expanded, so macros receive a uniform list representation. In this way, it's similar to wart's system, except that it's much more flexible and powerful.

---

"Does this make the grammar context-sensitive? Does it often introduce ambiguity? Have you run into non-terminating parsing?"

I have no idea, no, and no. It's all just simple list transformations, similar to what macros do.

---

"Can you talk about how it compares with oMeta? (Are you sure you aren't greenspunning it? :)"

I haven't use oMeta, but from what I understand, it uses something like PEG parsing, which is completely different.

Think of my system as being like macros: you take this list of symbols and that list of symbols and return this list of symbols.

The difference with macros is that my system has left/right associative, prefix/infix/suffix, precedence, and a slew of other options too.

The key insight is that unlike most syntax systems which return a single expression, Nulan's syntax system returns a list of expressions.

And then the syntax rules operate on this list, which effectively lets them look-behind and look-ahead arbitrarily many tokens, but only within the list.

PEG parsing lets you look-ahead as many tokens as you like, but not look-behind. Nulan's system supports both, but the amount of look-ahead/behind is controlled by the indentation, so everything is handled in a consistent way.

-----

2 points by Pauan 4149 days ago | link

To fully explain how the system works, let's use this program:

  prn 10 20
    foo bar + 50 * 20 - 30
After tokenizing, we use the significant whitespace rules to wrap the stuff in lists:

  {prn 10 20
    {foo bar + 50 * 20 - 30}}
Now, for each list, we run a modified Pratt parser on it:

https://github.com/Pauan/nulan/blob/79ea2a9fee8cb1ea7640d8f5...

Yes the Pratt parser really is that tiny. Now, let's start with this list:

  {foo bar + 50 * 20 - 30}
We start parsing at a precedence level of 0. First, we take all the non-syntax rule symbols and put them into a list. Now we have these two lists:

  left:      {foo bar}
  symbol:    +
  remaining: {50 * 20 - 30}
The + syntax rule has a precedence of 70. Now we need to recursively call the Pratt parser with a precedence of 70:

  left:      {50}
  symbol:    *
  remaining: {20 - 30}
The * syntax rule has a precedence of 80, which is greater than 70, so it continues parsing:

  left:      {50}
  symbol:    *
  right:     {20}
  remaining: {- 30}
The - syntax rule has a precedence of 70, which is equal to 70, so it stops parsing. It now calls the action function for * with the arguments left, symbol, and right, which returns {* 50 20}

Now we go back to the + syntax rule, which looks like this:

  left:      {foo bar}
  symbol:    +
  right:     {* 50 20}
  remaining: {- 30}
It calls the action function for + with the arguments left, symbol, and right, which returns {foo {+ bar {* 50 20}}}:

  left:      {foo {+ bar {* 50 20}}}
  remaining: {- 30}
Now it continues parsing with a precedence of 0. - has a precedence of 70 which is greater than 0, so it recursively calls the parser with a precedence of 70:

  left:      {foo {+ bar {* 50 20}}}
  symbol:    -
  right:     {30}
  remaining: {}
It now calls the action function for - which returns {foo {- {+ bar {* 50 20}} 30}}

We now call the Pratt parser on the outer list with a precedence of 0:

  left:      {prn 10 20 {foo {- {+ bar {* 50 20}} 30}}}
  remaining: {}
There aren't any syntax rules, so it just returns it unmodified, and so the final answer is:

  {prn 10 20
    {foo {- {+ bar {* 50 20}} 30}}}
---

Pratt parsers are absolutely amazing. They're very very short, easy to implement, very fast, and incredibly flexible.

If you want to learn more, I recommend these links:

http://eli.thegreenplace.net/2010/01/02/top-down-operator-pr...

http://javascript.crockford.com/tdop/tdop.html

http://effbot.org/zone/simple-top-down-parsing.htm

https://groups.google.com/forum/?fromgroups=#!topic/comp.pro...

http://journal.stuffwithstuff.com/2011/03/19/pratt-parsers-e...

I can also clarify things further, and provide a simple stripped-down version of Nulan's parser, if that helps to understand.

-----

2 points by Pauan 4149 days ago | link

I just made some changes to Nulan's parser. Now almost all the syntax is customizable:

https://github.com/Pauan/nulan/commit/b13e6477726cc111af4c23...

The changes are: renamed "action" to "parse", added in a "vertical" option, added in a "tokenize" function.

---

Now, significant whitespace is hardcoded, numbers are always 0-9, and symbols are anything that isn't a number or delimiter.

But everything else is customizable. Everything. Even comments, strings, and space/newline is customizable.

---

The new "tokenize" function lets you fairly easily add in new tokenizers, which is what string/comment/space/newline does.

---

The new "vertical" option is pretty cool too. It's currently only used by "|" and it means that this:

  foo bar
    | qux 1 2 3
    | corge 4 5 6
Is parsed like this:

  {foo bar
    | {qux 1 2 3
       corge 4 5 6}}
But the "|" syntax also specifies "separator", so it's further parsed to this:

  {foo bar
    | {{qux 1 2 3}
       {corge 4 5 6}}}
After running the "parse" functions, the final result is this:

  {foo bar
    {| {qux 1 2 3}
       {corge 4 5 6}}}
By the way, "|" is just like "do" in Arc, but I think it looks a lot nicer.

-----

1 point by akkartik 4149 days ago | link

Thanks! 'Pratt parsers' was precisely the phrase I was looking for :)

> > ..resolving function/macro calls to be anywhere in the list..

> Not quite.. This all happens before macros are expanded..

Yeah, that was exactly what I meant.

-----

2 points by lark 4149 days ago | link

I would use it.

Could "withs" be renamed to something shorter, like "vars"? Why "progn" and not "do"?

-----

1 point by akkartik 4150 days ago | link

I've been reading http://subjectivelisp.org/wiki/Differences_with_Nu and noticed that your definition of let permits multiple variables. I'm curious if you considered the use case of destructured binding:

  (let (a b) (list 3 4)
    ..)

-----

2 points by Pauan 4150 days ago | link

Shameless plug: this is how Nulan handles it:

  # Single binding
  w/var foo = 5
    ...
  
  # Multiple bindings, like "withs" in Arc
  w/var foo = 5
        bar = 10
    ...
  
  # Look, ma, destructuring works
  w/var {foo bar} = {1 2}
    ...

-----

1 point by akkartik 4150 days ago | link

Nice. What is the s-exp for each?

I've considered replacing with and just keeping the serial version. But I like encouraging myself to not worry about ordering as much as possible.

-----

2 points by Pauan 4149 days ago | link

Only supports a single variable currently, though it would be cool to support multiple:

  w/each x = {1 2 3}
    prn x
Nulan's macro system is not only hygienic, but it plays very nicely with customizable syntax too, as you can see in the definition of "w/each":

  $mac w/each -> {('=) x y} body
    w/uniq i len
      w/complex y
        'w/var len = y.length
           for (var i = 0) (i ~= len) (++ i)
             w/var x = y[i]
               body
And a couple more examples:

  # Simulating a `for` loop using a `while` loop
  $mac for -> init test incr body
    '| init
     | while test
         | body
         | incr

  for (var i = 0) (i < 10) (++ i)
    prn i


  # Simulating a `do..while` loop using a `while` loop
  $mac do -> body {('while) test}
    'while %t
       | body
       | if ~ test
           &break;

  var i = 0
  do
    | prn i
    | ++ i
    while (i < 10)
P.S. Sorry for hijacking the thread, but I've been itching to talk about Nulan, since I've made so much progress on it (as shown by the many commits on Github).

-----