Arc Forumnew | comments | leaders | submit | rocketnia's commentslogin
4 points by rocketnia 5838 days ago | link | parent | on: Class macros

I think you're right about it being frustrating to be pulled in multiple directions when choosing how to represent a data structure.

In Groovy, I'm pulled in one direction:

  class Coord { int x, y }
  ...
  new Coord( x: 10, y: 20 )
    + okay instantiation syntax
    + brief and readable access syntax: foo.x
As the project evolves, I can change the class definition to allow for a better toString() appearance, custom equals() behavior, more convenient instantiation, immutability, etc.

In Arc, I'm pulled in about six directions, which are difficult to refactor into each other:

  '(coord 10 20)
    + brief instantiation syntax
    + brief write appearance: (coord 10 20)
    + allows (let (x y) cdr.foo ...)
    - no way for different types' x fields to be accessed using the same
        code without doing something like standardizing the field order
  
  (obj type 'coord x 10 y 20)
    + brief and readable access syntax: do.foo!x (map !x foos)
    + easy to supply defaults via 'copy or 'deftem/'inst
  
  [case _ type 'coord x 10 y 20]
    + immutability when you want it
    + brief and readable access syntax: do.foo!x (map !x foos)
    - mutability much more verbose to specify and to perform
  
  (annotate 'coord '(10 20))
    + easy to use alongside other Arc types in (case type.foo ...)
    + semantically clear write appearance: #(tagged coord (10 20))
    + allows (let (x y) rep.foo ...)
    - no way for different types' x fields to be accessed using the same
        code without doing something like standardizing the field order
  
  (annotate 'coord (obj x 10 y 20))
    + easy to use alongside other Arc types in (case type.foo ...)
    + okay access syntax: rep.foo!x (map !x:rep foos)
  
  (annotate 'coord [case _ x 10 y 20])
    + immutability when you want it
    + easy to use alongside other Arc types in (case type.foo ...)
    + okay access syntax: rep.foo!x (map !x:rep foos)
    - mutability much more verbose to specify and to perform
(This doesn't take into account the '(10 20) and (obj x 10 y 20) forms, which for many of my purposes have the clear disadvantage of carrying no type information. For what it's worth, Groovy allows forms like those, too--[ 10, 20 ] and [ x: 10, y: 20 ]--so there's no contrast here.)

As the project goes on, I can write more Arc functions to achieve a certain base level of convenience for instantiation and field access, but they won't have names quite as convenient as "x". I can also define completely new writers, equality predicates, and conditional syntaxes, but I can't trust that the new utilities will be convenient to use with other programmers' datatypes.

In practice, I don't need immutability, and for some unknown reason I can't stand to use 'annotate and 'rep, so there are only two directions I really take among these. Having two to choose from is a little frustrating, but that's not quite as frustrating as the fact that both options lack utilities.

Hmm, that gives me an idea. Maybe what I miss most of all is the ability to tag a new datatype so that an existing utility can understand it. Maybe all I want after all is a simple inheritance system like the one at http://arclanguage.org/item?id=11981 and enough utilities like 'each and 'iso that are aware of it....

-----

1 point by shader 5838 days ago | link

I rewrote the type system for arc a while ago, so that it would support inheritance and generally not get in the way, but unfortunately I haven't had the time to push it yet. If you're interested, I could try to get that up some time soon.

-----

1 point by rocketnia 5838 days ago | link

Well, I took a break from wondering what I wanted, and I did something about it instead, by cobbling together several snippets I'd already posted. So I'm going to push soon myself, and realistically I think I'll be more pleased with what I have than what you have. For instance, Mine is already well-integrated with my multival system, and it doesn't change any Arc internals, which would complicate Lathe's compatibility claims.

On the other hand, and at this moment it's really clear to me that implementing generic doppelgangers of arc.arc functions is a bummer when it comes to naming, and modifying the Arc internals to be more generic, like you've done (right?), could really make a difference. Maybe in places like that, your approach and my approach could form an especially potent combination.

-----

2 points by rocketnia 5825 days ago | link

I finally pushed this to Lathe. It's in the new arc/orc/ folder as two files, orc.orc and oiter.arc. The core is orc.arc, and oiter.arc is just a set of standard iteration utilities like 'oeach and 'opos which can be extended to support new datatypes.

The main feature of orc.arc is the 'ontype definition form, which makes it easy to define rules that dispatch on the type of the first argument. These rules are just like any other rules (as demonstrated in Lathe's arc/examples/multirule-demo.arc), but orc.arc also installs a preference rule that automatically prioritizes 'ontype rules based on an inheritance table.

It was easy to define 'ontype, so I think it should be easy enough to define variants of 'ontype that handle multiple dispatch or dispatching on things other than type (like value [0! = 1], dimension [max { 2 } = 2], or number of arguments [atan( 3, 4 ) = atan( 3/4 )]). If they all boil down to the same kinds of rules, it should also be possible to use multiple styles of dispatch for the same method, resolving any ambiguities with explicit preference rules. So even though 'ontype itself may be limited to single dispatch and dispatching on type, it's part of a system that isn't.

Still, I'm not particularly sure orc.arc is that helpful, 'cause I don't even know what I'd use it for. I think I'll only discover its shortcomings and its best applications once I try using it to help port some of my Groovy code to Arc.

http://github.com/rocketnia/lathe

-----

1 point by shader 5837 days ago | link

Well, I guess we'll just have to find out ;)

And yes, I did modify arc's internals to be more generic. Basically, I replaced the vectors pg used for typing with lists and added the ability to have multiple types in the list at once. Since 'type returns the whole list, and 'coerce looks for conversion based on each element in order, we get a simple form of inheritance and polymorphism, and objects can be typed without losing the option of being treated like their parents.

-----

3 points by rocketnia 5839 days ago | link | parent | on: Class macros

For that example, what about just defining a 'walk method for every collection and defining 'each the way Anarki does?

  (mac each (var expr . body)
    `(walk ,expr (fn (,var) ,@body)))

-----

1 point by ylando 5839 days ago | link

"Each" can iterate over millions of elements; in this case, we can use class macros to remove the function calls.

-----

1 point by rocketnia 5840 days ago | link | parent | on: Problems with arc

Anyone have any ideas on how to allow macro indirection via namespaces without having first class macros?

Lathe's approach (where namespaces are friendly-name-to-unfriendly-global-name tables encapsulated by macros):

  arc> (use-rels-as ut (+ lathe-dir* "utils.arc"))
  #(tagged mac #<procedure: nspace-indirect>)
  arc> (macex1 '(ut (xloop a list.7 b 0 a.b)))
  (gs2012-xloop a list.7 b 0 a.b)
  arc> (macex '(ut (xloop a list.7 b 0 a.b)))
  ((rfn next (a b) a.b) list.7 0)
  arc> (ut:xloop a list.7 b 0 a.b)
  7
Maybe we should try and design a set of very basic namespace handling tools, and then allow users to extend off of them.

Funny, that's part of what I had in mind as I made Lathe's module system. :-p Is there some aspect of Lathe's namespace handling that's inconsistent with what you have in mind? The point of the Lathe module system is mainly to keep the rest of the Lathe utilities safe from name conflicts, so I'll gladly swap it out if we can come up with a better approach.

(In case you haven't heard me rant about Lathe before, you can get to my original blog post about the module system via http://arclanguage.org/item?id=11610 and see all the current Lathe code at http://github.com/rocketnia/lathe. )

-----

4 points by rocketnia 5844 days ago | link | parent | on: Suggestion: how to improve arc.

It was just there for a brief pause between the macroexpansions of declare and undeclare.

If we want to change the behavior of other macros for a certain region of code, then that pattern might be useful. Since we seem to be talking about static type declarations, which I presume would be taken into account at macro-expansion time, I think the "between the macroexpansions" behavior is the whole point.

-----

1 point by fallintothis 5842 days ago | link

Thank you for the insight. It's probably the most lucid I've been all thread. It didn't seem deliberate to me, but it could have feasibly been written that way to control other macros' expansions. This also pushes computation to expansion time, which might clarify ylando's objections about "wasting run time". Except those still confuse me: macro expansion happens once, inside a function's body or outside of it.

  arc> (mac m (expr)
         (prn "macro m has expanded")
         expr)
  #(tagged mac #<procedure: m>)
  arc> (def f (x)
         (m (+ x 1)))
  macro m has expanded
  #<procedure: f>
  arc> (f 1)
  2
But the original point seems lost because declare's story keeps changing. So, ylando: why do we need "ignores"?

-----

1 point by ylando 5841 days ago | link

why do we need "ignores"?

Try building a macro that change global value, expand code (with macros) and then change the value back. I think that this macro must use another macro to change the value back; like the undeclare macro above. The second macro expands into unnecessary code; so if you put it inside a function this unnecessary code will waste run time. If we have "ignore" macro, we can write macros that do not produce unnecessary code.

-----

4 points by fallintothis 5840 days ago | link

I think that this macro must use another macro to change the value back; like the undeclare macro above.

Not necessarily.

  (mac declare (name prop . body)
    (let old (metadata* name)
      (= (metadata* name) prop)
      `(after (do ,@body)
         (= (metadata* ',name) ,old))))
But this introduces redundant assignments after each execution of body. Using a macro that expands into "unnecessary code" can be cheaper.

  (mac declare (name prop . body)
    (let old (metadata* name)
      (= (metadata* name) prop)
      `(after (do ,@body)
         (undeclare ,name ,old))))

  (mac undeclare (name old)
    (= (metadata* name) old)
    nil)
This introduces a redundant nil in the after block, and using after is a bit slower than just a do1. But we can't use do1 because this "do all the work at macro-expansion" approach is so touchy that it breaks:

  arc> (load "macdebug.arc") ; see http://arclanguage.org/item?id=11806
  nil
  arc> (macwalk '(declare name prop a b c))
  Expression --> (declare name prop a b c)
  macwalk> :s
  Macro Expansion ==>
    (do1 (do a b c)
         (undeclare name nil))
  macwalk> :s
  Macro Expansion ==>
    (let gs2418 (do a b c)
      (undeclare name nil)
      gs2418)
  macwalk> :s
  Macro Expansion ==>
    (with (gs2418 (do a b c))
      (undeclare name nil)
      gs2418)
  macwalk> :s
  Macro Expansion ==>
    ((fn (gs2418)
       (undeclare name nil)
       gs2418)
     (do a b c))
  macwalk> :s
  Subexpression -->
    (fn (gs2418)
      (undeclare name nil)
      gs2418)
  macwalk> :s
  Subexpression --> (undeclare name nil)
  macwalk> :s
  Value ==> nil
  Value ==> gs2418
  Value ==> (fn (gs2418) nil gs2418)
  Subexpression --> (do a b c)
  macwalk> :a
  Value ==> (do a b c)
  Value ==>
    ((fn (gs2418) nil gs2418) (do a b c))
  ((fn (gs2418) nil gs2418) (do a b c))
Note that we reach undeclare before the actual body is expanded!

We can hack it without after or do1 (or mutation, but I avoid that anyway).

  (mac declare (name prop . body)
    (let old (metadata* name)
      (= (metadata* name) prop)
      (w/uniq (g1 g2)
        `(with (,g1 (do ,@body)
                ,g2 (undeclare ,name ,old))
           ,g1))))

  (mac undeclare (name old)
    (= (metadata* name) old)
    nil)
This way, declare expands in the right order and we only undeclare once, since it'll expand into nil. The nil is "unnecessary", which seems to be why you want ignore, but it's a terribly pedantic point: ignore is already accomplished by dead code elimination (http://en.wikipedia.org/wiki/Dead_code_elimination). This isn't even a case of "sufficiently smart compilers" for vanilla Arc, since mzscheme already implements the standard optimizations: function inlining, dead code elimination, constant propagation/folding, etc. (see http://download.plt-scheme.org/doc/html/guide/performance.ht...) should all be able to clean up whatever ac.scm generates. E.g.,

  (mac foo ()
    `(prn ',metadata*!name))

  (declare name bar (foo))
compiles to

  ((lambda (gs581 gs582) gs581)
   ((let ((| gs581| (lambda () (ar-funcall1 _prn 'bar)))) | gs581|))
   'nil)
which should be easy to optimize.

Worrying seems premature anyway. ac.scm and arc.arc themselves do plenty worse, and the differences here are essentially rounding error.

  arc> (time10 (w/stdout (outstring)
                 (repeat 1000000
                   (with (x (do (prn 'bar))
                          y nil)
                     x))))
  time: 43048 msec.
  nil
  arc> (time10 (w/stdout (outstring)
                 (repeat 1000000
                   (prn 'bar))))
  time: 43170 msec.
  nil
Final idea: if expansion-time computation can't be avoided, you can expand the macros manually, if only for the sake of your readers. As a bonus, it does away with the dead code.

  (mac declare (name prop . body)
    (let old (metadata* name)
      (= (metadata* name) prop)
      (do1 `(do ,@(map macex-all body)) ; see http://arclanguage.org/item?id=11806
           (= (metadata* name) old))))
However, I think the fragile expansion-time computation is a bigger issue than dead code.

-----

1 point by ylando 5840 days ago | link

I try:

  (def macex-all (e)
    (zap macex e)
    (if acons.e
        (map1 macex-all e)
        e))

  (mac declare (name prop . body)
    (let old (metadata* name) 
       (= (metadata* name) prop)  
       (let exp-body (macex-all body)
            (= (metadata* name) old)
            (cons 'do exp-body))))
and it works. thanks.

-----

3 points by rocketnia 5845 days ago | link | parent | on: html.arc: another approach

Why use parentheses at all?

  (x:a href "http://arclanguage.org onclick "alert();"
    "click here")
The body can be distinguished from the attribute-value pairs thanks to either the fact that it doesn't begin with a symbol or the fact that there's nothing to pair it with.

-----

2 points by evanrmurphy 5844 days ago | link

Wow, neat idea! I'm looking into it right now...

And Arc continues on its quest to become the most parens-frugal Lisp there ever was. :P

Question: Do y'all like the x:a? It seems kludgy to me and I'd rather just do a, but maybe I'm missing the point...

-----

2 points by rocketnia 5844 days ago | link

Wow, neat idea! I'm looking into it right now...

Oh, I guess sml.arc already allows for that syntax. XD I should have taken a closer look....

Anyway, in case it helps, Lathe has a utility called parse-magic-withlike defined here: http://github.com/rocketnia/lathe/blob/master/arc/modules/mo...

It does save a single pair of parentheses every once in a while, but it takes half a page of comments to explain comprehensively. :-p Then again, it's meant for Arc macros in general, so some of the idiosyncracies might disappear if it's modified for a specific purpose like this one.

Do y'all like the x:a?

I thought the "x:a" was just an abbreviation for things like "w/html:a", "html:a", "tohtml:a", and "sml:a", substituting whatever you decided the macro name would be. What alternative are you thinking about?

-----

2 points by evanrmurphy 5844 days ago | link

> I thought the "x:a" was just an abbreviation for things like "w/html:a", "html:a", "tohtml:a", and "sml:a", substituting whatever you decided the macro name would be.

The "x:a" originally came from the example at http://en.wikipedia.org/wiki/SXML#Example, where I think it had another meaning - maybe something to do with XHTML... anyway, it's probably not important. You clarified that I wasn't missing something in the conversation (unless we both are ;).

-----

2 points by shader 5844 days ago | link

I think in the x:a syntax, the x part is supposed to denote the xml namespace in which the tag is defined. It's used in things like xpath.

-----

1 point by rocketnia 5844 days ago | link

I think so too. The x is defined here at the beginning of the example:

  (*TOP* (@ (*NAMESPACES* (x "http://www.w3.org/1999/xhtml")))
   ...
There's an okay introduction to namespace usage in XML and SXML here: http://www196.pair.com/lisovsky/xml/ns/

-----

1 point by rocketnia 5852 days ago | link | parent | on: Initial problems

As you demonstrate, your file does not contain the same thing as the original command you used. I think it would help to replace ".com" with ".scm".

By the way, to use preformatted text, indent each line with two spaces. Also, you can use asterisks for italics. There's actually an instruction page for this somewhere, but I can't find the link either, so no worries. :-p

Also, I don't mean to burst your bubble, but the main Arc page gives old installation instructions. You don't have to get an old MzScheme version as long as you get arc3.1.tar. http://arclanguage.org/item?id=10254

-----

3 points by fallintothis 5852 days ago | link

http://arclanguage.org/formatdoc

-----

3 points by akkartik 5852 days ago | link

It's really too bad that link's no longer around textareas. The only place HN and this forum link to it is in edit textareas..

-----

2 points by rocketnia 5853 days ago | link | parent | on: Ideas about arc object system.

What do you like about having an object system, specifically? I wouldn't mind having one too, but I think object systems get complicated and arbitrary very quickly. I'd rather not have one monolithic abstraction where several highly-focused ones would do.

I do find myself switching to Groovy a lot thanks to its object system. I think what I mainly like is the ability to make an instance of FooSubclass and automatically have "foo in FooSuperclass" and "foo in FooInterface" be true.

Using Arc's built-in notion that the type of an object is the result of calling the 'type function on it (which is configurable via 'annotate), it's easy enough to achieve a form of inheritance that accomplishes what I just described:

  ; This is a table from type symbols to lists of their supertypes.
  ; Indirect supertypes are included in these lists, but no type is a
  ; member of its own list. There are no inheritance loops, either;
  ; inheritance here is a directed acyclic graph, and this is the
  ; transitive closure of that graph.
  (= indirect-inheritance* (table))
  
  (def inherits (subtype supertype)
    (~~mem supertype (cons subtype indirect-inheritance*.subtype)))
  
  (def fn-def-inherits (subtype . supertypes)
    (each supertype supertypes
      (when (~inherits subtype supertype)
        (when (inherits supertype subtype)
          (err "There was an inheritance loop."))
        (let supers (cons supertype indirect-inheritance*.supertype)
          (zap [union is supers _] indirect-inheritance*.subtype)
          (each (k v) indirect-inheritance*
            (when (mem subtype v)
              (zap [union is supers _] indirect-inheritance*.k)))))))
  
  (mac def-inherits (subtype . supertypes)
    `(fn-def-inherits ',subtype ,@(map [do `',_] supertypes)))
  
  (def isinstance (x test-type)
    (inherits type.x test-type))
  
  (def a- (test-type)
    [isinstance _ test-type])
Come to think of it, I can't think of anything else object-oriented I miss in Arc. (OO is good for dispatch too, but I've already made an Arc dispatch library I like better.) I'll make sure to try this out the next time I program something substantial in Arc.

So, I've talked a lot about me, but my question to you still stands. What features are you looking for in an object system?

-----

3 points by ylando 5852 days ago | link

In my own opinion:

The most important feature of object oriented is name compressing. Imagine a program with a lot of different databases. Now you have to give names for functions that add element, You will have to give them names like:

  add-worker, add-statistic, add-html-text ...
Now you have to remember all those names.

-----

3 points by rocketnia 5851 days ago | link

That sounds like dispatch to me. ^_^ You'd like to use one name but give it multiple meanings based on the types involved. This thread (http://arclanguage.org/item?id=11779) has a couple of approaches to dispatch from akkartik and myself.

Hmm, I've been having trouble for a while, trying to figure out my favorite way to have inheritance and multiple dispatch at the same time. (Single dispatch with inheritance seems more straightforward, but I'd rather not bother with it if I could use multiple dispatch instead.) If one method signature is (A, B) -> C, and another is (B, A) -> C, and A is a subtype of B, then what happens if you call the method with (a, a)? That could just cause an error, or the first argument could take precedence, but I'm not sure which approach I like better.

-----

1 point by ylando 5851 days ago | link

I think that multi dispatch is good idea for strong type languages. If c++ encounters this problem it will solve it at compile time (I think it will try to find the solution that is best for the first variable then the second and so on). For a dynamic language like arc multi dispatch will have an efficiency cost. In my own opinion:

It is one of the "too smart to be useful" features of common lisp. It is one of the reason people hate clos.

I have a question for you: In what way a multi dispath is better then the alternatives? You can dispatch only on the first argument or hold a virtual table of functions for every object.

-----

1 point by rocketnia 5851 days ago | link

For a dynamic language like arc multi dispatch will have an efficiency cost.

I don't think the efficiency cost for dynamic dispatch on the first argument would be significantly different, and I'm not worried about either one. I think they're at worst as inefficient as a sequence of if statements, which is to say they would take constant time (given a constant number of methods to check and constant time for each check).

Constant time can still be painful in the right quantity, and making the decision at compile time would indeed help, but Arc doesn't have the necessary static type information to go on (as you know). So multiple dispatch and single dispatch alike have to suffer a bit.

It is one of the reasons people hate clos.

Well, I've heard nothing but good things about CLOS, but then I haven't heard that much. ^_^ Is there some good anti-CLOS reading material you can recommend? XD

In what way is multi dispatch better then the alternatives?

It's partly a matter of name compression. ^_-

  ; no dispatch
  (collide-spaceship-with-spaceship s s)
  (collide-spaceship-with-asteroid s a)
  (collide-asteroid-with-spaceship a s)
  (collide-asteroid-with-asteroid a a)
  
  ; single dispatch (on the first argument)
  (collide-with-spaceship s s)
  (collide-with-asteroid s a)
  (collide-with-spaceship a s)
  (collide-with-asteroid a a)
  
  ; double dispatch
  (collide a s)
  (collide s a)
  (collide a s)
  (collide a a)
Yeah, I stole Wikipedia's example here. Another example is a comparison function that needs to compare values of many different types. Yet another is a "write" function which has different behavior for each type of writer object and each type of object to be written.

When it comes right down to it, I just believe multiple dispatch ought to be a simpler concept than single dispatch, since it imposes fewer restrictions on the programmer. Unfortunately, it seems to replace one arbitrary restriction with a bunch of (what I see as) arbitrary design decisions. ^_^;

-----

0 points by ylando 5851 days ago | link

For every one of your examples, we can use double dispatch design pattern; For example:

  (collide o1 o2) call 
  (collide-with-spaceship o2 o1) if o1 is a spaceship
  or (collide-with-asteroid o2 o1) if o1 is an asteroid.
I think that you can even abstract this design pattern with a macro (but I did not try it). So you still did not convince me that multi dispatch is a good feature.

-----

3 points by rocketnia 5853 days ago | link | parent | on: Problems with arc

At the risk of sounding like a broken record, I think Lathe's namespaces already embody lots of the ideas people are talking about here. :-p

In this case, Lathe provides two forms in its more-module-stuff.arc module, 'packing and 'pack-hiding, which work like 'packed but only put certain parts of the "my" namespace into the package object. That way, the internals don't get imported.

The 'packing and 'pack-hiding forms are in a separate module only because they aren't fundamental to Lathe, but in fact, I've never actually wanted to use them. Just having separate namespaces is enough for me, 'cause when I want to have unobtrusive definitions, I can just create a throwaway namespace to put them in.

-

@evanrmurphy http://arclanguage.org/item?id=11975

For what it's worth, Lathe's namespaces are used like this, generally:

  (--specify-what-creates-the-namespace--
    --specify-functions-etc-using-the-namespace--)
The main point of this in Lathe is so that the form can clean up after itself using an 'after form. The return value capability is also nice.

An alternate namespace implementation might take this format so that it could search-and-replace names in its body at macro-expansion time. That was my original plan for Lathe's namespaces, but I soon realized a simplistic code walker wouldn't do, and I didn't really want to write a sophisticated code walker unless I had a whole new language in mind. Also, I doubt this approach would translate very well to the REPL.

-----

3 points by rocketnia 5855 days ago | link | parent | on: Problems with arc

1) I think you're missing the whole point of 'let.

  arc> (= x 5)
  5
  arc>
    (let x 3         ; "declare" a var with value 3
      (= x (* x x))
      (+ x 2))
  11
  arc> x
  5
If you want to separate the declaration from the initial value... why? What happens if you use the variable in between those two times?

2) For what it's worth, my Lathe library provides a certain sort of namespaces, and I've been using those pretty happily. (http://arclanguage.org/item?id=11610) But of course I'd be happy with them, 'cause I'm their author. :-p

3) Why would you need a macro to expand to...

  (w/alias (var this.var var2 this.var2)
    (def myfunc (this arg1 arg2)
      ...))
...when it could already expand to something like this?

  (def myfunc (this arg1 arg2)
    (with (var this!var var2 this!var2)
      ...))
That said, I think 'symbol-macro-let would be nifty. I wonder if it could be even more useful to have some way to build a lambda whose free variables were treated in a custom way (as opposed to just being globals). Either one of these could be a basis for scoped importing of namespaces.

-----

4 points by rocketnia 5858 days ago | link | parent | on: Adding local scope to arc

First off, two bugs: You use 'append rather than 'join, and 'shuffle_numbers will overwrite the global variable 'i since 'i isn't a lexical variable at (= i (- max min)) and (-- i). There might a third bug where you say (~is (caar lst) 'fn), but I'm not sure what your intention is there.

Next, there are some things you can simplify. In shuffle_members, you have "let temp 0 @", which isn't doing much, and you also have "@ arr" at the end, which is unnecessary. Unlike 'let, 'w/table automatically returns the value its variable has at the end of the body. In span_let, there's a place where you check [and (is (type _) 'cons) (is (car _) 'scope)], but FYI, that's exactly what [iscar _ 'scope] does. :) Also, I don't expect you to know this right away, but you can accomplish the decreasing loop using (down i (- max min) 1 ...); 'down is a backwards 'for.

Finally, it's really not a big deal, but these names would be more consistent with Arc:

  binding-function-list*
  span-let
  shuffle-numbers
I think that the scope macro make the code more readable. What do you think?

I don't really think it makes it more readable, but that's only because it introduces new rules I'm not accustomed to. The "let temp 0" line is clearly supposed to wrap the whole area, but I had to open up Arc and check to see whether the 'for loop wrapped the 'loop loop or not. (Your indentation might have been a clue, but I suspected a bug.)

In total, you removed ((()())) and put in (scope @ @ @ @) and some extra rules to worry about. I think that's sort of a net loss. But hey, it could be the basis for a better idea. If it helps you read your code, then I think it's worth it already. ^_^

-----

1 point by fallintothis 5858 days ago | link

that's exactly what [iscar _ 'scope] does.

In vanilla Arc, [caris _ 'scope].

-----

1 point by rocketnia 5857 days ago | link

Typo. XP Thanks.

-----

1 point by ylando 5858 days ago | link

Thanks for your nice responce. It was very helpfull. Append works in jarc but i didn't find any document on this function.

-----

More