Arc Forumnew | comments | leaders | submitlogin
2 points by akkartik 4631 days ago | link | parent | on: An update on wart

This seems really useful. I got the motivation off the bat, but I still don't understand the spec. Can you give an example session showing how functions are defined, and how they are called?
2 points by rocketnia 4631 days ago | link | parent | on: An update on wart

"The next one refers to s and str as well. Is that intended?"

Yes. Only <s> appears in the pattern itself, but the meaning of <str> is explained by "...where <str> is the string name of the symbol <s>."

---

"Also, I don't follow the distinction between the string case and the symbol case."

Did you see this part? -- "(That may look simple enough, but a completely different symbol pattern applies when matching a list element. See below.)"

A symbol which occurs in a list acts as a hybrid keyword/positional argument. A symbol by itself acts just like a string.

---

Sorry I'm being terse with this stuff. I found it hard to express my points in informal English, which is why I went with a spec document style in the first place.

Let's see...

My motive is to show you a way your desired features can be accomplished in an extensible ravioli style, rather than one big chunk of spaghetti. What you want is achievable with a simple enough collection of parser combinators, although sometimes their interfaces may be unusual due to expression evaluation being part of the parsing process.

For instance, in the system I gave, the parser combinators use a few unusual design patterns:

- The combinators must take in an evaluation environment.

- The combinators frequently quote a value so they can pass it off to another combinator that may eval it again. (I think I've seen you use this style before, actually.)

- The combinators must sometimes return the evaluated expression, just so that the (<a> | <b>) pattern can avoid double evaluation.

Another important point I'm making is that you probably don't need to reorder the argument list for the purposes of keyword arguments. My system instead (effectively) reorders the parameter pattern so the keywords are processed first.

I got this system a bit wrong because I don't support multiple keyword aliases for the same parameter. My (<a> | <b>) pattern instead binds multiple parameter variables to the same argument value, so I got that backwards.

1 point by akkartik 4631 days ago | link | parent | on: An update on wart

The next one refers to s and str as well. Is that intended?

Also, I don't follow the distinction between the string case and the symbol case.

2 points by rocketnia 4631 days ago | link | parent | on: An update on wart

Oops, in one of those rules I said <s> where I meant <str>. Here's the corrected version:

  <str>  ; where <str> is a string
Evals the current expr and binds the variable named <str> to the result value.

Found it: https://github.com/svetlyak40wt/arc-crawler. Awesome.
2 points by rocketnia 4632 days ago | link | parent | on: An update on wart

Whoops, I forgot alias support entirely! Ah well, I'll just leave it this way for now.
2 points by rocketnia 4632 days ago | link | parent | on: An update on wart

In case it helps (or just drives a discussion), I've ironed out my own design spec for the features you're going for.

It's not quite the same as what you're describing. For one thing, it doesn't include the new restrictions you're talking about.

For another thing, it includes a new pattern type. Symbols have a lot of duties in your patterns because they deal with evaluation and keywords. I found it easiest to separate symbol patterns into two different types of patterns, only one of which deals with keywords. The non-keyword patterns I represent as strings (just to distinguish them from symbols). It would be easy to replace this with a special form or with some other literal type.

...Oh, I guess you don't have an explicit keyword parameter syntax either. I assumed you did, so it's in here too. (It could actually help clarify what's going on here. The symbol pattern deals with keywords and does just a bit more on top of that, so I like the side-by-side comparison.)

---

The pattern language has several kinds of patterns. A pattern operates on a single unevaluated s-expression (henceforth "expr") and an evaluation environment, and it outputs a map of variable bindings. It also outputs an evaluation result, if it evaluates the expr as part of its processing. (The evaluation result is only used for (<a> | <b>) patterns, to prevent duplicate evaluations.)

These are the available patterns:

  <str>  ; where <str> is a string
Evals the current expr and binds the variable named <s> to the result value.

  <s>  ; where <s> is a symbol
Runs the pattern <str> on the current expr, where <str> is the string name of the symbol <s>.

Uses those variable bindings and that evaluation result.

(That may look simple enough, but a completely different symbol pattern applies when matching a list element. See below.)

  '<a>
Runs the pattern <a> on a quoted version of the current expr.

Uses all variable bindings produced by <a>.

  ()
Evals the current expr. If the result isn't nil, raises an error.

  ; any cons cell
Does several special things depending on the contents of the pattern's cons cell:

  (<a> | <b>)
Runs pattern <a> on the current expr.

If that pattern returned an evaluation result, runs pattern <b> on a quoted version of that result value. Otherwise, runs pattern <b> on the current expr.

Uses all variable bindings produced by <a> and <b>, preferring the bindings in <b>.

Uses the evaluation result of <a> or <b> if available, preferring the result of <b>.

  (<before...> <k> <v> ... <rest>)
    ; where <before...> is any number of non-keyword, non-symbol
    ; elements; <k> is a keyword; and <rest> could be anything,
    ; especially an improper list
This pattern treats the current expr as an unevaluated improper list, looking for the first occurrence of <k> with another element after it (which we will refer to as the value expr).

If the keyword binding is found: Matches <v> against the value expr. Matches <rest> against an alteration of the current expr, changed to remove the keyword and the value expr. Uses all variable bindings produced by <v> and <rest>, preferring the bindings in <rest>.

If the keyword binding is not found: Matches the pattern <rest> against the entire expr. Uses those variable bindings.

  (<before...> <s> ... <rest>)
    ; where <before...> is any number of non-keyword, non-symbol
    ; elements; <s> is a symbol; and <rest> could be anything,
    ; especially an improper list
Let <k> be the keyword with the same name as the symbol <s>, and let <str> be this name as a string.

This pattern treats the current expr as an unevaluated improper list, looking for the first occurrence of <k> with another element after it (which we will refer to as the value expr).

If the keyword binding is found: Matches <str> against the value expr. Matches <rest> against an alteration of the current expr, changed to remove the keyword and the value expr. Uses all variable bindings produced by <str> and <rest>, preferring the bindings in <rest>.

If the keyword binding is not found: Matches the pattern (<str> ... <rest>) against the entire expr. Uses those variable bindings.

  ; for any other kind of cons cell...
  (<a> ... <b>)
Evals the current expr. If the result isn't a cons cell, raises an error. Otherwise, runs the patterns <a> and <b> on quoted versions of the result's car and cdr.

Uses all variable bindings produced by <a> and <b>, preferring the bindings in <b>.


By the way, I discovered it with my tool, which I'm writing in Arc to learn this language. This tool crawls GitHub starting from Anarki repository, to find other interesting projects, written in Arc.

There was a thread about this recently that was a lot of fun: http://arclanguage.org/item?id=17597

Ooh, I'd never seen this one before!
2 points by malisper 4632 days ago | link | parent | on: How do I use a library?

Since you are not running arc from the arc folder, you need to use either the full path, or the path relative from where you are running arc. If you are running arc in dir/foo/ and the file is in dir/bar/lib/http.arc, you could use:

  (require "../bar/lib/http.arc")

Wow, I forgot about another my founding:

  * https://github.com/mgiken/arc-mg - improved Arc3.1 version with libraries and bindings even to libcurl (1 year)

By the way, is there an IRC channel or some other place for more informal talks?

Well, probably I should ask another question, addressed to the different implementations' authors: "Why do you started to write your own implementation instead of making efforts to improve Anarki?" :)

I don't know how to answer it :) There's a lot of code in the world. I can help answer questions on some of it, but I have no idea what's most promising.

I upvoted you because I was happy to see the list, and I'd be interested in other people's answers.


So, why nobody wants to discuss this topic?

If pg ever contributes a line of code to anarki I'll eat my hat :) Not that that's a bad thing; it works perfectly well for each side to port changes from the other.
1 point by bh 4632 days ago | link | parent | on: Is there no way to make an http request?

I wonder what will happen to Arc now that pg has passed YC on to Sam? How is he going to pick up work again? Will he just keep working on arc 3.1, or will he just contribute to anarki?
2 points by shader 4632 days ago | link | parent | on: Is there no way to make an http request?

Well, from a cursory glance, there are at least two libraries in the anarki lib directory:

  https://github.com/arclanguage/anarki/blob/master/lib/http.arc
  https://github.com/arclanguage/anarki/blob/master/lib/web.arc
There might be more, but these should get you started.

I should probably mention that most of that documentation is probably targeted at the the vanilla arc 3.1, which is the lowest common denominator at this point for all of the arc implementations. Every other arc implementation has its own set of additional libraries, and usually a way to access libraries from its host language. I.e., anarki also includes multiple ways to call racket code directly.

3 points by shader 4632 days ago | link | parent | on: Rewriting in to accept a list?

I think it might help to point out how the macro expands there:

  (inl 1 '(1 2 3))
is transformed by the reader to

  (inl 1 (quote (1 2 3)))
which is then macro expanded by

  `(in ,elt ,@lst)
where elt is bound to '1, and lst is bound to '(quote (1 2 3)). This means that when lst is spliced in, you get:

  '(in 1 quote (1 2 3))
As stated, the problem is largely the choice of macro instead of function. Macros are primarily useful to control evaluation; they do not evaluate their arguments by default. A macro will only let you work with the literal input, not their values. You can't (with arc) have your cake and eat it too; you can only work with either the syntax, or the values. You wouldn't be able to do something like:

  (let x '(1 2 3)
     (inl 1 x))
for instance, because it would attempt to treat the symbol 'x as if it were a list to be spliced, not the value of x. That's why you need a function, like pos.
1 point by akkartik 4633 days ago | link | parent | on: Rewriting in to accept a list?

  arc> (inl 1 (list 1 2 3))
  t
I wouldn't rely on that:

  arc> (inl list (list 1 2 3))
  t
  arc> (let x list
         (prn list)
         (inl list (list 1 2 3 4)))
  #<procedure: list>
  t
So you're actually searching a list that includes the function list.

"..you don't want to pass a quoted list into a macro, but unquoted. This is the way most macros are used, but I hesitate to make it a global rule."

The rule is, the arg is eval'd if it's eval'd in the expansion. (Since macros don't eval args, they eval the return value.)

  (mac foo (x) (cons 3 ,x))  ; will eval x
  (mac bar (x) (cons 3 ',x))  ; won't eval x
2 points by zck 4633 days ago | link | parent | on: Rewriting in to accept a list?

>Sorry, I know this isn't Stack Overflow, but virtually no one follows the arc-lisp tag there, and I don't know anywhere else to post.

Don't worry about this. I'm happy whenever anyone's talking about Arc. I'd love to have the problem that people are posting too much here.

I've been confused by this issue too. There are two things here.

1. First, instead of using 'in, you can use 'pos:

    arc> (pos 1 '(1 2 3))
    0
2. Let's make your macro work anyway:

First, reproduce:

    arc> (inl 1 '(1 2 3))
    Error: "_quote: undefined;\n cannot reference undefined identifier"
Huh, it works if you use 'list:

    arc> (inl 1 (list 1 2 3))
    t
Or without 'list:

    arc> (inl 1 (1 2 3))
    t
This is interesting. Let's use 'macex1 to see what happens:

    arc> (macex1 '(inl 1 '(1 2 3)))
    (in 1 quote (1 2 3))
So the problem is that '(1 2 3) really is a list with two things in it: the symbol 'quote and the list (1 2 3). I'm a little bit uncomfortable with this explanation, but this seems to mean that you don't want to pass a quoted list into a macro, but unquoted. This is the way most macros are used, but I hesitate to make it a global rule. Some day I'll understand macros better.
2 points by akkartik 4633 days ago | link | parent | on: Rewriting in to accept a list?

You can see what your macro expands to:

  arc> (macex1 '(inl 1 '(1 2 3)))
  (in 1 quote (1 2 3))
That probably explains the error message. (Quotes expand to the symbol quote.)

So all you have to do is not quote your argument:

  arc> (inl 1 (1 2 3))
  t
As a general rule, however, try not to use a macro unless you have to. In this case there's a pure function that does what you want:

  arc> (pos 1 '(1 2 3))
  0
  arc> (pos 4 '(1 2 3))
  nil
(You can use pos in a conditional just like inl because it is guaranteed to only return nil if and only if the element doesn't exist.)

More info: http://arclanguage.github.io/ref/list.html#pos. As an exercise try implementing pos for yourself :) And feel free to ask us more questions! I hadn't realized there were questions at stack overflow. I'll try to hang out there, but there's really nothing off-topic here.

2 points by bh 4633 days ago | link | parent | on: How can I build a list of lists quickly?

Wow, awesome answer. Thanks!

Short answer: to reproduce the exact example you have...

  arc> (n-of 3 (range 0 9))
  ((0 1 2 3 4 5 6 7 8 9) (0 1 2 3 4 5 6 7 8 9) (0 1 2 3 4 5 6 7 8 9))
Long answer:

Depends on what you're trying to do. :)

I could sit here and rattle off builtin Arc helper functions & macros, but there's a bigger lesson to be learned here about functional programming. Specifically, the list comprehensions you naturally gravitate towards are just syntactic sugar for the famous map & filter higher-order functions (https://en.wikipedia.org/wiki/Map_(higher-order_function) & https://en.wikipedia.org/wiki/Filter_(higher-order_function)).

In Python (at least in Python 2.x, where map and filter return lists instead of generators), the equivalence looks like this:

  [expr_involving_x for x in xs]      == map(lambda x: expr_involving_x, xs)
  [x for x in xs if expr_involving_x] == filter(lambda x: expr_involving_x, xs)
For example,

  >>> [x + 1 for x in [1,2,3]] == map(lambda x: x + 1, [1,2,3])
  True
  >>> [x for x in [1,2,3] if x == 2] == filter(lambda x: x == 2, [1,2,3])
  True
You can apply these transformations recursively until you remove the list comprehension notation altogether. E.g.,

  [x + 1 for x in [1,2,3] if x == 2] -> map(lambda x: x + 1, [x for x in [1,2,3] if x == 2])
                                     -> map(lambda x: x + 1, filter(lambda x: x == 2, [1,2,3]))
Nested comprehensions have a transformation rule, too, but it's somewhat more complicated:

  [expr_involving_y for x in xs for y in expr_involving_x] == sum([[expr_involving_y for y in expr_involving_x] for x in xs], [])
For example,

  >>> [y+1 for x in [1,2,3] for y in [x+1,x+2,x+3]] \
  ... == sum([[y+1 for y in [x+1,x+2,x+3]] for x in [1,2,3]], []) \
  ... == sum([map(lambda y: y+1, [x+1,x+2,x+3]) for x in [1,2,3]], []) \
  ... == sum(map(lambda x: map(lambda y: y+1, [x+1,x+2,x+3]), [1,2,3]), [])
  True
So, list comprehensions are just a way of saying the same things as higher-order functions. Arc generally favors the higher-order function flavor of this idiom. map is still called map, filter is called keep, and Python's sum(..., []) is spelled (apply join ...):

  arc> (map (fn (x) (+ x 1)) (list 1 2 3))
  (2 3 4)
  arc> (keep (fn (x) (is x 2)) (list 1 2 3))
  (2)
  arc> (apply join (map (fn (x) (map (fn (y) (+ y 1)) (list (+ x 1) (+ x 2) (+ x 3)))) (list 1 2 3)))
  (3 4 5 4 5 6 5 6 7)
You might think Arc's preference for these comes from Lisp dialects naturally eschewing specialized syntax. But, Arc does like syntactic shortcuts; just ones that apply more generally to functions, like bracket notation (e.g., [+ _ 1]) and ssyntax (e.g., ~f and f:g come up a lot in higher-order calls).

It's also interesting to note that due to the previous rules, you can easily write a macro that turns list comprehensions into the equivalent chain of higher-order function calls.

There are many Arc builtins that can help build lists, too. They're all defined in Arc itself, so just take a look through arc.arc to figure out how they work. Functions I spy that may help for list building (list of lists or otherwise): rem, mappend, trues, firstn, nthcdr, cut, tuples, pair, n-of, bestn, split, retrieve, dedup, reduce, rreduce, range, ... Really just depends on what you're looking to do!

2 points by shader 4636 days ago | link | parent | on: Is there a repository of Arc libraries?

Indeed. I've put several libraries there myself.

I might be interested in working on something like packages.el for emacs that supports grabbing arc libs directly from github.

Dependency management may be somewhat tricky, but we could leave that up to the library creators to manage. Or work on yet another package system...

2 points by akkartik 4639 days ago | link | parent | on: How to see a full traceback in anarki?

Indeed, this is wonderful. I've updated anarki.

Wow, this is very helpful even without source locations!
4 points by rocketnia 4640 days ago | link | parent | on: How to see a full traceback in anarki?

I took a look at http://docs.racket-lang.org/reference/exns.html and found something that works.

Look for these lines in ac.scm:

                (display "Error: ")
                (write (exn-message c))
Replace them with this:

                ((error-display-handler) (exn-message c) c)
Before:

  arc> (+ 1 (fn))
  Error: "cadr: contract violation\n  expected: (cons/c any/c pair?)\n  given: '(fn)"
  arc> (def foo () (map [+ 1 (fn ())] list.nil))
  #<procedure: foo>
  arc> (foo)
  Error: "+: contract violation\n  expected: number?\n  given: #<procedure: foo>\n  argument position: 2nd\n  other arguments...:\n   1"
After:

  arc> (+ 1 (fn))
  cadr: contract violation
    expected: (cons/c any/c pair?)
    given: '(fn)
    context...:
     C:\mine\prog\repo\anarki\ac.scm:24:22: ac
     C:\Program Files (x86)\Racket\collects\racket\private\map.rkt:26:19: loop
     C:\mine\prog\repo\anarki\ac.scm:486:0: ac-call
     C:\mine\prog\repo\anarki\ac.scm:1218:4
  
  arc> (def foo () (map [+ 1 (fn ())] list.nil))
  #<procedure: foo>
  arc> (foo)
  +: contract violation
    expected: number?
    given: #<procedure: foo>
    argument position: 2nd
    other arguments...:
     1
    context...:
      map1
     C:\mine\prog\repo\anarki\ac.scm:1218:4
In these examples, the first error happens during macroexpansion, when the compiler is processing the 'fn special form. The second error happens at run time. They both recover to the REPL just fine.

The second stack trace doesn't include 'foo or 'map, but I bet that's because they made a call in tail position, leaving no trace of their stack frame. Let's change 'foo so it doesn't do that:

  arc> (def foo () (map [+ 1 (fn ())] list.nil) nil)
  *** redefining foo
  #<procedure: foo>
  arc> (foo)
  +: contract violation
    expected: number?
    given: #<procedure: foo>
    argument position: 2nd
    other arguments...:
     1
    context...:
      map1
      foo
     C:\mine\prog\repo\anarki\ac.scm:1218:4
Yep, looking good. :)

Arc seems to throw away source location information, but I think we could get that back too if we tried. It'll involve using Racket syntax objects somehow.

Thanks for speaking up about this. This seems like something that could help a lot of people. XD

3 points by lark 4642 days ago | link | parent | on: How to read mutable hash tables

Thank you for writing up such a clear explanation.

There are definitely safety benefits to using the simplest form. But I would prefer to use the most general form (withs) because I won't need to worry about using the most idiomatic form or to switch from one form to another as the program changes. It frees me to worry about other things.

Being able to tell simpler parts from more complex parts at a single glance isn't as much of a concern for me. I noticed I don't go back to even read code of programs that didn't solve a big enough problem. The programs reach a dead end and don't develop further. There are more important things to worry about when writing a program.

Also note what let, with, and withs offer could be provided in other languages too. Them being implemented as macros in Arc is incidental. You're not giving up the benefits of lisp by not using them.

More