Arc Forumnew | comments | leaders | submit | eds's commentslogin
1 point by eds 6667 days ago | link | parent | on: Does Arc need modules? Maybe not.

Then why don't you just eval prefix?

  `(def ,(read (+ (coerce (eval prefix) 'string) "-" (coerce name 'string))) ,args ,@body)
It's still much less clunky than expanding the whole def under an eval.

-----

1 point by cchooper 6667 days ago | link

Still has a bug:

  (let pre2 'blub (your-def-with-prefix pre2 foo (x) (+ 1 x)))
  => Error: "reference to undefined identifier: _pre2"

-----

2 points by cooldude127 6667 days ago | link

that's because the macro gets expanded (and thus eval is called on pre2) before the let form is evaluated.

-----

1 point by eds 6667 days ago | link

Yeah, I see the problem with that.

cchooper, did you actually ever run your version? I can't make your orginal version work.

  arc> (def-with-prefix pre foo (x) (+ 1 x))
  Error: "reference to undefined identifier: _x"
And looking at the macro expansion, I'm not at all surprised:

  arc> (macex '(def-with-prefix pre foo (x) (+ 1 x)))
  (eval (list (quote def) ; my indentation
              (read (+ (coerce pre (quote string)) "-" (coerce (quote foo) (quote string))))
              (x) (+ 1 x)))
args and body would need to be quoted for this to work properly. And then it admittedly does what it is supposed to, but it becomes even uglier.

  (mac def-with-prefix (prefix name args . body)
    `(eval (list 'def
            (read (+ (coerce ,prefix 'string)
                     "-"
                     (coerce ',name 'string)))
            ',args
            ,@(map [list 'quote _] body))))

-----

1 point by cchooper 6667 days ago | link

Hmmm... it worked last night. I must have made a mistake when I copied it into the comment. Thanks for catching it.

Here's a slightly less clunky version:

  (mac def-with-prefix (prefix name args . body)
    `(eval (join (list 'def 
                  (sym (+ (coerce ,prefix 'string)
                          "-"
                          (coerce ',name 'string)))
                  ',args)
            ',body)))
I also tried doing it with nested quasiquotes but that just looked worse.

-----

2 points by eds 6667 days ago | link | parent | on: Implicit progn

There was a post a while ago about a form of let that managed to mix both multiple assignments and implicit progn behavior, although if I recall correctly it had problems with destructuring binds.

  (let var1 expr1
       var2 expr2
       ...
       (form1 ...)
       (form2 ...)
  )
http://rondam.blogspot.com/2008/02/z-shrtr-bttr.html

The post in question was actually about conciseness as a metric, and the example used in his argument was exaggerated to make his point, but the form he created (the modified let) might actually be useful (although the last stage of his example was a little scary... maybe we shouldn't take it all the way).

-----

5 points by aidenn0 6667 days ago | link

I don't think mixing the two is good. I think the lack of implicit progn would be a Good Thing. The explicit progn makes non-functional code stand out, and it also makes the language a bit more uniform if no primitives have implicit progn. All other things being equal uniformity is good because it reduces surprises. Unless there are a lot of people who feel like the implicit progn is an important part of "let" I'd prefer to not have it.

-----

1 point by bOR_ 6583 days ago | link

nice link, and he makes some good points on keeping away from uberbrevity. Maybe we should let and with rest ;).

-----

3 points by eds 6668 days ago | link | parent | on: Modules : a proposition

I know this doesn't address many of the issues with a module system in arc... but there is currently an import.arc file in the arc-wiki that has a few interesting points.

In the current import.arc, when you import a module, the name of the module gets set to a macro which allows you to access functions in the module via composition. Thus you get to use : rather than another arbitrarily chosen character. I just thought that was kind of cool.

  arc> (load "lib/import.arc")
  nil
  arc> (imp array)
  #3(tagged mac #<procedure>)
  arc> array
  #3(tagged mac #<procedure>)
  arc> array:array?
  #<procedure>
  arc> (array:array? 1)
  nil
Maybe there is a problem with just simple composition that doesn't scale when applied to a full blown module system. But if you could incorporate this into any ideas currently going around, I think it would clean up the syntax for accessing internals of a module at the very least.

-----

1 point by eds 6669 days ago | link | parent | on: Top 10 differences between Scheme and Arc

From the arc side of things it may look like () and nil are the same, but on the scheme side of things, nil is a symbol, not at all related to the empty list ().

And as a matter of fact, arc lists are indeed terminated with the symbol nil.

  > mzscheme -m -f as.scm
  Use (quit) to quit, (tl) to return here after an interrupt.
  arc> (cdr '(1))
  nil

  > mzscheme
  Welcome to MzScheme version 352, Copyright (c) 2004-2006 PLT Scheme Inc.
  > (cdr '(1))
  ()
and also

  arc> '(1 . nil)
  (1)
  arc> '(1 . ())
  (1)

  > '(1 . nil)
  (1 . nil)
  > '(1 . ())
  (1)
the second arc example '(1 . ()) evaluates to (1) but still results in a nil terminated list

  arc> (cdr '(1 . ()))
  nil
The fact that nil and () happen to be equivalent in arc has nothing to do with whether lists are nil or () terminated.

And I could have sworn I had gotten an error once that showed that an arc list had gotten into scheme somehow, but I can't remember exactly what I did to cause the error right now. I think it was something like:

  Error: some function expected a proper list but got '(3 + 4 . nil) instead.

-----

1 point by nlavine 6669 days ago | link

On the contrary, the question of how a particular implementation represents with arc lists has nothing to do with what arc lists are.

In fact, you could make ac.scm more efficient by doing a (define nil '()), eliminating all the denil stuff, and then changing the print routines, if you cared to.

-----

3 points by kens 6668 days ago | link

Is ac-niltree/ac-denil a constant overhead, or does it make some O(1) operations into O(n) operations? Hopefully the nil/denil traverses the whole list only when you're already traversing the whole list. But I haven't been able to convince myself that's always the case. This is on my list of things to investigate, but has anyone already figured this out?

-----

1 point by eds 6668 days ago | link

I'm not completely sure, but I think this is a compile-time overhead. So when you type directly into the toplevel, its a O(n) overhead, but when you execute a function defined in arc, executing the function itself should be less additional overhead because it was compiled to a scheme function in the original def.

  ; translate fn directly into a lambda if it has ordinary
  ; parameters, otherwise use a rest parameter and parse it.
  (define (ac-fn args body env)
    ; ...

-----

2 points by nostrademons 6668 days ago | link

Have to watch out for corner cases - Arc's usage of 'nil as the list terminator is exposed in several places within the language itself. For example `(is (coerce "nil" 'sym) (cdr nil))` is true under the existing implementation, yet would be false if you just (defined nil '()). You'd need to patch `is`, `coerce`, and possibly a bunch of other primitives to preserve the existing behavior.

-----

1 point by almkglor 6668 days ago | link

Which exposes the problem of "the code is the spec". If there was a prose spec, pg could have just said that such stuff was undefined and we wouldn't care that such things break.

-----

3 points by akkartik 6668 days ago | link

If stuff doesn't work right, having the spec say it's supposed to not work right doesn't help at all.

Prose specs came into being to help multiple implementations interoperate (somewhat) when implemented in low level languages. I don't see the need when you have just one pretty concise and declarative implementation.

-----

1 point by eds 6668 days ago | link

The question of how a particular implementation represents with arc lists has nothing to do with what arc lists are.

The code is the spec.

The fact remains that in arc when you type '(a b c) you get '(a . (b . (c . nil))) and in scheme you get '(a . (b . (c . ()))).

You could make ac.scm more efficient by doing a (define nil '())

There is a difference between nil being the empty list and nil evaluating to the empty list.

One problem with (define nil '()) is that then 'nil returns the symbol nil rather than the empty list ().

I am not convinced that (define nil '()) would greatly increase efficiency, because most of that overhead is incurred in the initial read, and not at run time. It takes billions of times longer for the user to type a statement into arc than it takes arc to denil the input. And after that, nil or () isn't an issue because arc functions are compiled to scheme functions anyways.

-----

2 points by absz 6668 days ago | link

I'm fairly sure that "the code is the spec" applies to arc.arc, not to ac.scm. That is, anything that can interpret arc.arc properly is a conforming Arc implementation; ac.scm is just one of them. And since nil is (), then in Arc, your two lists are the same but with different formatting. Observe:

  arc> (is nil '())
  t
  arc> (is nil ())
  t
  arc> (iso '(a b c) '(a . (b . (c . nil))))
  t
  arc> (iso '(a b c) '(a . (b . (c . ()))))
  t
  arc> (iso '(a . (b . (c . nil))) '(a . (b . (c . ()))))
  t

-----

2 points by eds 6668 days ago | link

Please note that the behavior of is is defined by ac.scm, not arc.arc. (And iso uses is to test for equality.)

The equality and interchangability of nil and () is just because there is a line in the definition of is that specifically says that false values are equal.

  (xdef 'is (lambda args
              (tnil (or (all (lambda (a) (eqv? (car args) a)) (cdr args))
                      (and (all string? args)
                           (apply string=? args))
                      (all ar-false? args)))))
  
  (define (ar-false? x)
    (or (eq? x 'nil) (eq? x '()) (eq? x #f)))
So even if you put #f in the terminating position, your lists will still be iso.

  arc> (iso '(a b c) '(a b c . #f))
  t
Are you saying that arc lists are #f terminated just because it doesn't break arc to put #f in random lists? Even if arc lists can be terminated by nil, (), and #f, it doesn't mean they necessarily are. Any given list (ignoring nested lists) can only have one termination object. I think it is reasonable to say that that list is terminated by that object. I do not think it is reasonable to say that list is terminated by another object, even if it could be, because the actual object at the end of the list is not that other object. And because the current implementation (the only official implementation) uses nil, I think it reasonable to say that arc lists are terminated by nil. Note the use of the present tense. If that changes at some future time, I my statement will obviously not apply.

-----

2 points by absz 6668 days ago | link

What you say is true, except for one thing:

  arc> (is #f nil)
  t
In short, given the current implementation, we have (at least) six different ways to write nil: nil, 'nil, (), '(), #f, and '#f. These six things are all considered identical within Arc. The same is true, for instance, of 'a and (quote a), which are the same thing entered differently. You can check that they are the same with is; I won't put all those examples into this post.

I have never said that Arc lists aren't nil terminated--clearly, they are. What I'm saying is that Arc lists are nil terminated for any representation of nil--whether that representation is nil from Common Lisp, '() from Scheme, or #f from a leftover artifact of using the mzscheme reader.

-----

1 point by eds 6670 days ago | link | parent | on: Infix Math

I've been working on a version of infix syntax written in arc that relies only on the ability to switch the first and second places in a function call when the functional position contains a number. This means that the solution relies on minimal changes to ac.scm, and can be loaded either automatically or optionally into the running arc toplevel.

I also added setter forms so the user can now define precedence of an operator as such:

  (= (precedence %) 2)
or

  (= (precedence %) /)
And I also experimented with pg's other suggestion for literals being constant functions when in functional position. I found you can have both that and switching arguments at the same time, for example:

  [3] ; always evaluates to 3
  (3 + 4) ; same as (+ 3 4)
  (3 + 4 * 5 - 6) ; when using my infix library
This version being written directly in arc, it is probably slower than the scheme version. But considering it is much less intrusive to ac.scm, I will probably push this version to the arc-wiki.

The code can be obtained at the following url:

http://blackthorncentral.net/files/infix.arc

Changes to ac.scm required to make this work:

  (define (literal? x)
    ; ...
    (procedure? x) ; to allow (eval `(,+ 3 4))

  (define (ar-apply fn args)
    ; ...
    ((or (number? fn) (symbol? fn)) ; (3 + 4) means (+ 3 4)
     (if (pair? args) (apply (car args) fn (cdr args)) fn))

-----

1 point by eds 6667 days ago | link

Pushed this to the arc-wiki.

This means that infix.arc now gets loaded by default when arc starts. Since infix.arc redefines the existing +-/* operators, if you don't want this to happen when arc loads, you can remove it from the list in libs.arc, then load it or not at your leisure.

-----


Um....

Sacado said: "Well, actually, to do so, I had to make effective the optimisation someone there already wrote about, in arc< and arc>."

-----

5 points by sacado 6671 days ago | link

In fact, both were needed to optimize things. Mzscheme's doc says explicitly (though I can't remeber where exactly) that standalones are a little faster than interpreted code (there are a few more optimisations they can perform during compilation I guess). Running arc1.scm through mzscheme -f is a little slower.

-----

4 points by elibarzilay 6671 days ago | link

There is an initial overhead for byte-compiling the code and jitting it -- but that's not something that you'd be able to measure for such a small piece of code. Once that's done, it's the same code -- mzscheme (since a good while ago) on intel and ppc does not interpret code. Ever. Even on solaris, where the jit is disabled, it's "interpreting" byte-compiled code, so it is not an interpreter in any case.

-----

2 points by elibarzilay 6671 days ago | link

Right, these two are major bottlenecks. (There are still a good number of them that can be optimized.)

-----

1 point by eds 6671 days ago | link | parent | on: Eval Inquirry

Thanks, although it seems to regard mostly macros.

PG commented "The single biggest compromise I had to make because of MzScheme was not being able to put objects like functions and hashtables into macroexpansions." Not exactly sure what he meant by that, or if it had anything to do with the evaling functions directly.

I guess what I am really wondering is if there is an intrinsic reason why evaling a function directly can't work, or if support for it just doesn't happen to be in Arc currently because PG never needed it.

-----

3 points by cadaver 6671 days ago | link

From the tutorial:

  [Note: Like functions, hash tables can't be printed out in a way
  that can be read back in.  We hope to fix that though.]
The problem that I see with macros+hashtables in macroexpansion, as well as with printing/reading-back-in functions+macros+hashtables, is that currently an expression is compiled, before it is evaled, and loses its original uncompiled form. That's why macros are currently not truly first-class.

If used with eval or in macroexpansions this only causes a problem with macros and hashtables, not with functions or hashtables used as functions. Like nlavine pointed out, it only takes an additional line of code in "ac" to make your example work.

-----

2 points by soegaard 6670 days ago | link

Hash tabels ought to be easy to fix by setting the MzScheme parameter print-hash-table to #t. See

http://download.plt-scheme.org/doc/352/html/mzscheme/mzschem...

-----

1 point by eds 6671 days ago | link | parent | on: Infix Math

Although literals in functional position may be valuable real estate, I think that infix math is valuable enough to justify using it (at least until we think of something more important).

The only other thing that was suggested in the comment in ar-apply was that literals in functional position might be constant functions. I think infix syntax gives the programmer far more expressive power than being able to denote constant functions.

-----

1 point by eds 6671 days ago | link | parent | on: Notation for s-expressions using indentation

I took a shot at writing an indentation based syntax a while ago. You don't technically need the colons, although that makes it difficult to introduce new parens mid-line.

http://arclanguage.org/item?id=1917

I like the idea of indentation based syntax, but the colon solution looks like only half a solution. You only remove half the delimiting characters, and the ones you remove are the ones that are the easiest to type when you have a good editor. (In fact, some editors even add them for you.) Considering that I prefer parens to colons as delimiters, I would currently prefer to stay with s-expressions.

And as much as I might like indentation based expressions, kennytilton has a good point about editing code. In indentation based syntaxes, you have to redo the indentation manually (or rely on an editor to guess), whereas in traditional lisp you can just hit the auto indent key (since indentation can be determined programmatically).

-----

1 point by applepie 6671 days ago | link

The colon proposal attempts to be orthogonal to traditional s-expression notation (every s-expression in traditional notation keeps reading the same as always, no matter how it is formatted).

> I like the idea of indentation based syntax, but the colon solution looks like only half a solution

Well, if we want to read s-exprs, _somehow_ the programmer must hint the reader about where the parens go.

I don't want the reader to guess what I mean, or juggle with whitespaces.

I think the colon notation is more visually appealing than "just parens", and doesn't hurt programmers who don't want to use it.

-----

2 points by cadaver 6671 days ago | link

Since, as I've pointed out, the editor can handle the parens for you completely and unabiguously, even without any special commands, you could simply turn-off, parens that exist in addition to indentation, make them invisible.

If you then additionally make the editor display the opening parenthesis as a colon then, voila, you have the visually pleasing colon syntax.

In such a mode you'd always have to be indentation perfect, but just as with colon syntax, you can simply switch to a more traditional editing mode.

-----


Very nice. Both your suggested commands worked for me (on Windows XP).

I like the GUI especially (it actually solves a bug I found with mzscheme that was stopping me from pasting code directly into the command line). Although I find it somewhat strange that I have to click quit twice in order to actually close the program.

-----

1 point by ryantmulligan 6671 days ago | link

does the first click close Arc and the second close MrEd?

-----

1 point by eds 6671 days ago | link

Yes.

  Use (quit) to quit, (tl) to return here after an interrupt.
  arc> (quit)
  
  [Exited]
Clicking close after this closes the window. Similarly, clicking close twice seems to first send a break signal, then close the window.

I kind-of understand why it is doing this, but it might be nice to have it quit immediately when the user enters (quit).

-----

More