
Show HN: `diff arc0 arc3.1` - laarc
https://cdn.rawgit.com/laarc/notebook/757f7eff5cb26d2ae98dc732252d66fd0e6507c6/arc0-3.1.html
======
laarc
If you have questions, please ask! Using Arc in real applications has been
such an interesting experience that I can barely shut up about how
ridiculously fun it is.

Here are some unfinished notes about what the diffs mean:
[https://gist.github.com/laarc/a07799e89940dc7c31c9](https://gist.github.com/laarc/a07799e89940dc7c31c9)
It's interesting how short the diffs are vs how many features and fixes they
deliver.

~~~
voltagex_
The only Arc application I know of is HN - can you show any other examples?

As a non-Lisp programmer, can you sell the benefits of Arc to me?

~~~
d0m
Here's an example of why arc/lisp are great:

    
    
        (mac awhen (expr . body)
          `(let it ,expr (if it (do ,@body))))
    

This basically add a new syntax to the language. How often did you do in
python:

    
    
        some_value = my_function()
        if some_value:
          call_something_with(some_value)
    
    

With the small macro defined earlier, we can do:

    
    
        (awhen (my_function)
          (call_something_with it))
    
    

Basically, binding (my_function) to the variable named "it".

It's amazing to be able to add new syntax/features to the language without
having to wait for a new version. Imagine if you could add any features you
want to javascript or python without having to wait 5 years for the spec to be
approved and implemented..

It's possible because the code is written in the same data structure that you
use to manipulate normal values. I.e.:

    
    
        (let x 1
          (prn x))
    

Is the code of the program but _also_ simply a list of 4 elements. And since
the code itself is a data structure that you can manipulate with normal
functions, there's something called "Macro" in Lisp (not to confuse with C++
macros), which essentially are functions that receive code and returns code,
instead of receiving values and returning values.

So: (some_macro (prn 1)). some_macro would receive a list of two elements (prn
and 1) and could do some operation to it and returns some new code.. such as
(prn 2), which will then get evaluated to print 2. Whereas (some_fn (prn 1))
would evaluate (prn 1) (which returns nil), and pass nil to some_fn.

That's why it's so hard to impress a lisp programmer with any other languages
because if a feature doesn't exist, they can add it with a macro. I.e. Actors
or OO, or whatever really.

~~~
millstone
I don't know much about LISP. What you showed looks nice and useful, but I
would not consider it new syntax.

Is it possible to use this technique to introduce, say, infix arithmetic
operators, or ObjC's dot syntax? Or can you just trade one S-expression for
another?

~~~
laarc
_ObjC 's dot syntax?_

Sure. That's easy in Lumen:
[https://github.com/sctb/lumen/commit/6410c8cc2de66d1976515bd...](https://github.com/sctb/lumen/commit/6410c8cc2de66d1976515bdd71ab9b65c12cbf10#diff-910c7ff4864f437a8c67427b7b055657R70)

 _Is it possible to use this technique to introduce, say, infix arithmetic
operators?_

Yep! I wrote a macro to swap any instance of `x with the previous expression.
Meaning, it allows you to write:

    
    
      (foo `= (x `+ y))
    

rather than

    
    
      (= foo (+ x y))
    

The reason it was so easy to do this is because `foo is shorthand for
(quasiquote foo). So the macro simply steps through a body of code, looks for
any instance of quasiquote followed by an atom, and then swaps it with the
previous expression.

But more generally, it's easy to write a macro to do whatever you want. If you
really want infix expressions all of the time, I could imagine writing a macro
which matches the pattern (... + ... + ...) and replaces it with (+ ... ...
...)

That's made-up notation, but the idea is just "look for some set of symbols,
like + or /, which occur within a list in between all of the other elements,
and then move the symbol to the front of the list."

The power is available to you, but whether you choose to use it is a separate
question. Prefix notation tends to be a win for everything except math. And
even for math, it's usually a matter of code formatting. Rather than

    
    
      (- (* 2 (/ (+ x y) (+ a b c))) 1)
    

try

    
    
      (- (* 2
            (/ (+ x y)
               (+ a b c)))
         1)
    

or

    
    
      (let u (+ x y)
        (/= u (+ a b c))
        (*= u 2)
        (-- u))
    

Once Laarc has support for indentation-as-parens, it'd look like:

    
    
      let u (+ x y)
        /= u (+ a b c)
        *= u 2
        -- u
    

which is rather pretty, and has no ambiguity. One of pg's essays on Arc
mentioned this feature, and it seems like a good idea, so I hope to pursue it.

~~~
akkartik
0\. Is Laarc an arc variant you're working on? I don't see it on the github
page.

1\. You might be interested in how my arc-inspired language did indent-
sensitivity and infix:
[http://akkartik.name/post/wart](http://akkartik.name/post/wart). For example,
here's bresenham's line-drawing algorithm in wart:
[https://gist.github.com/akkartik/4320819](https://gist.github.com/akkartik/4320819).
There are more code samples at
[http://rosettacode.org/wiki/Category:Wart](http://rosettacode.org/wiki/Category:Wart).

2\. Do you have a username on arclanguage.org? Perhaps we've met!

~~~
laarc
It is indeed. I'm in the process of porting from Racket to Lumen. It's taking
a bit, and it'll be tricky to add true greenthread support to js and lua, but
it's a win so far.

Wart is freaking cool! Thanks for showing that. Whoaaa, you use tangle/weave!
How do you like it / what do you think about literate programming? I was
batting around the idea of writing code that way, but it seemed like tangle
might not be the best solution. But I love your 000prefix naming scheme; I
instinctively do that for branches. After reading through a few files starting
at
[https://github.com/akkartik/wart/blob/master/literate/000org...](https://github.com/akkartik/wart/blob/master/literate/000organization)
it became pretty clear how wart worked, pretty quickly. I'm mainly wary of the
"compile" step that using Tangle implies; do you find it slows you down much?
Would you choose to do it that way if starting fresh?

 _What would a language ecosystem be like without any backwards-compatibility
guarantees, super easy to change and fork promiscuously?_

It's fun to find someone has been mulling over the same problems!

I was considering taking Laarc in a similar direction:

    
    
      (import "akkartik/foo")
    

That would check whether the folder "../foo/akkartik" exists, and if not,
clone foo from github.com/akkartik/foo.

It would also rewrite its own source code to look like:

    
    
      (import "akkartik/bar" "f1d2d2f924e986ac86fdf7b36c94bcdf32beec15")
    

That means whenever someone clones your codebase, running the program would
cause them to clone github.com/akkartik/bar using commit f1d2d2f9.

So it's static linking, basically. It's a guarantee that "This source code
will always work, the same way (+ 1 2) will always yield 3. You could copy-
paste this source code into a gist, and whoever ran it would end up running
the same program."

That removes dependency hell / worrying about versions entirely. But it's not
the right solution, and I've been searching for a better one. What do you
think?

The problem is that it throws away the ability for the code to pull updates
from library maintainers. If the import is "pinned" at commit f1d2d2f9, then
you push a security-related patch to akkartik/bar, most existing code will
stay vulnerable forever, because most code is never maintained after being
written.

I was thinking of following that model, but using the convention that
libraries are expected to use git tags in order to indicate major.minor.patch,
and (import "akkartik/bar" "f1d2d2f924e986ac86fdf7b36c94bcdf32beec15") will
bump itself to the next commit if it's tagged as an increment of the patch
version.

What kind of things have surprised you about Wart during development? Any
unexpected pitfalls or interesting discoveries along the way? Thanks again for
pointing it out!

By the way, were there any ambiguities with indentation-as-parens? I haven't
thought about it rigorously, so I was just wondering if there are any corner
cases to watch out for when I add it.

~~~
akkartik
Thanks for the kind words! I'm particularly gratified that you found the
literate/ subdirectory. There's some details about it at
[http://akkartik.name/post/wart-layers](http://akkartik.name/post/wart-
layers), but it sounds like you understand the point already so I'm preaching
to the choir :)

 _" What kind of things have surprised you about Wart during development?"_

I stopped working on wart at some point for two reasons. First, I realized
that I was falling into a blind spot shared with many contemporary
programmers: blindly assuming that the way to improve the state of programming
was by creating a new language. But there is more to programming than
languages. Languages just happen to be memetically tempting sirens to chase
after. Second, I painted myself into a corner with wart because I made it
_too_ late-bound, so late-bound that it was incredibly inefficient and so hard
to optimize. (I think it might still be possible, but I lost patience partly
because of the previous point.) I still like my infix scheme and have a
particularly soft spot for the way wart allows keyword arguments anywhere in
any function call. See, for example, the use of _:from_ in a webserver
implementation that makes everything so much clearer:
[https://github.com/akkartik/wart/blob/ce64882c69/071http_ser...](https://github.com/akkartik/wart/blob/ce64882c69/071http_server.wart#L17).
However, I've forced myself to harden my heart and ruthlessly ignore
considerations of syntax, and focus on what I think are more impactful
directions: conveying global rather than local structure of programs. More
details: [http://akkartik.name/about](http://akkartik.name/about). In brief,
I'm working on ways to super-charge automatic tests (by making them white-box,
and by designing the core OS services to be easy to test) and version control
(using the literate layers you noticed). It's a whole new way of programming
where a) readers can ask "why not write this like this?", make a change, run
all tests and feel confident that the change is ok if all tests pass; and b)
readers can play with a simple version of the program running just layer 1,
then gradually learn about new features by running layers 1+2, 1+2+3, and so
on.

\---

 _" The problem is that it throws away the ability for the code to pull
updates from library maintainers. If the import is "pinned" at commit
f1d2d2f9, then you push a security-related patch to akkartik/bar, most
existing code will stay vulnerable forever, because most code is never
maintained after being written."_

I hadn't considered hard-coding hashes in imports, because it's historically
been very hard to truly distinguish compatible changes from incompatible ones
without introducing bugs. I think it's more important to give people control
over upgrades than to try to improve over the current advisory+pull method of
communicating security issues.

You're right that most code is never maintained after being written. But most
code is also utterly unimportant to anyone including the author. So that
failure of security is ok :) Trying to force concern about security only
increases the moral hazard -- people get used to other people thinking about
their security for them.

 _" were there any ambiguities with indentation-as-parens? I haven't thought
about it rigorously, so I was just wondering if there are any corner cases to
watch out for when I add it."_

The big insight, I think, is to not fear parentheses too much. A common
failure mode of such approaches (like
[http://readable.sourceforge.net](http://readable.sourceforge.net) and
[http://dustycloud.org/blog/wisp-lisp-
alternative](http://dustycloud.org/blog/wisp-lisp-alternative)) is to create
too many new token types and lose the simplicity of lisp syntax. My approach
instead is to a) just use parens sooner than look "outright barbarous"
([https://www.mtholyoke.edu/acad/intrel/orwell46.htm](https://www.mtholyoke.edu/acad/intrel/orwell46.htm)),
and b) take it a step further and disable all indent-sensitivity inside
parentheses.

Anyways, that's my two cents. The precise rules I use are at
[https://github.com/akkartik/wart/blob/master/004optional_par...](https://github.com/akkartik/wart/blob/master/004optional_parens).
(They're really in the first couple of sentences there.)

\---

 _" Whoaaa, you use tangle/weave! How do you like it / what do you think about
literate programming?"_

Like I said above, I like it very much, especially in combination with tests
and a notion of layers. Here's my take on why literate programming has failed
so far: [http://akkartik.name/post/literate-
programming](http://akkartik.name/post/literate-programming)

~~~
d0m
I've also been following your work akkartik by the way :] Sneaking from time
to time on the arc forum. Keep up the great work!

~~~
akkartik
I too was thinking on this thread that I remembered you from the arc forum :)

------
hark1234
pg is that you? :)

