Arc Forumnew | comments | leaders | submit | shader's commentslogin

That's exactly what I was originally thinking, only I didn't know that .value == [_ value]. Makes a lot of sense, actually.

I second the motion for maintaining and leveraging the integrity of arc's style, as opposed to fighting bitterly against it.

-----

1 point by shader 5599 days ago | link | parent | on: Class macros

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 5599 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 5587 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 5599 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.

-----

1 point by shader 5602 days ago | link | parent | on: Eliminate modules from ac.scm?

Just wondering, but why do you want to remove the module information?

-----

1 point by akkartik 5602 days ago | link

Part of my attempt at refactoring arc (http://arclanguage.org/item?id=11880) - I want to be able to split ac.scm into multiple files.

-----

1 point by shader 5605 days ago | link | parent | on: stdout vs. return values (re: html.arc)

Btw, I found almkglor's whtml.arc: http://github.com/nex3/arc/blob/arc2.master/whtml.arc

There's a lot of good stuff that apparently got left behind in the old arc2 branches.

-----

3 points by shader 5605 days ago | link | parent | on: stdout vs. return values (re: html.arc)

By printing directly to stdout you don't get to have as many tail calls, but you don't have to worry about much complexity when it comes to aggregating output or adding new functionality. A simple pr is all it takes to add output, and you don't need to worry much about context.

One alternative is functions that take lists as input, and cons in their own output before passing them on to the next level. Then use a final translation function that walks the tree converting it to text using something like the sml parser. Unfortunately this means you have to walk the code twice, once for content generation and once for output transformation.

The pros of the first system are simplicity, efficiency, and compatibility with a socket based web server (just redirect stdout to the socket)

The second system has the advantage of decoupling content from presentation at the cost of complexity managing aggregation, and walking the tree twice.

-----

2 points by shader 5606 days ago | link | parent | on: Problems with arc

What about = is unsafe? Are you saying that you might accidentally assign to a misspelled variable?

-----

1 point by ylando 5606 days ago | link

Are you saying that you might accidentally assign to a misspelled variable?

Yes this is exactly the problem. This the reason perl has: use strict.

-----

2 points by shader 5606 days ago | link | parent | on: html.arc: another approach

I'd like to add the comment that I think everyone who has gone to the trouble of writing useful code should put it somewhere accessible, such as GitHub or Anarki, so that we can continue to find it later even after the article is buried.

Several times the only discoverable implementation of useful code is the discussion on the forum, which can be quite difficult to find later, and also challenging to get to in a way that's easy to use.

-----

3 points by shader 5606 days ago | link | parent | on: html.arc: another approach

I'd be interested to know what you think of almkglor's 'w/html. It was mentioned on the related thread you posted. The interesting feature is that all tag symbols are quoted, so you don't need a php-style escape for arc code.

-----

3 points by evanrmurphy 5606 days ago | link

I'm quite impressed, actually! In addition to the name (which in itself beats my (html (html problem), the quoting system seems smart. I'm going to have to mull this over more.

Another punctuation possibility I've considered that's different from both of these is quasi-quotation,

  (tohtml     ; another decent name
    `(body
      (h1 "Simple Math")
      (p "1 plus 1 equals " ,(+ 1 1))

  ; would generate:
  ; <body><h1>Simple Math</h1><p>1 plus 1 equals 2</p></body>nil

which would seem like a very natural way to escape into Arc. Not only does it look better, but it could get me out of using 'eval in that 'htmlf function. In fact, the more I write about this, the better it sounds. I think I'll give quasi-quotation a shot.

-----

3 points by shader 5606 days ago | link

I think that

  `(body
    (h1 "Simple Math")
    (p "1 plus 1 equals " ,(+ 1 1))
and

  ('body
    ('h1 "Simple Math")
    ('p "1 plus 1 equals " (+ 1 1))
are probably equivalent, though I don't know how quoting affects strings. Odds are the same system could handle both styles, which means that programmers could use whichever they prefer. Personally I like the 'tag notation for tags, but hopefully it would be flexible enough to handle both.

What's the current status of whtml.arc? I can't look at the repo right now. Does it look like something that could be used as is?

-----

1 point by evanrmurphy 5606 days ago | link

> probably equivalent

I agree that they seem close and are probably one macro apart from behaving the same, but they must be different since the latter throws

  Error: "Can't coerce  body fn"
while the former returns a list. I think its equivalent normal-quoted expression would have to be something more like:

  (list 'body
    (list 'h1 "Simple Math")
    (list 'p "1 plus 1 equals " (+ 1 1)))
I haven't found whtml at http://github.com/nex3/arc/tree/master/lib/ yet. I did however just stumble upon sml.arc by akkartik, which appears to be super relevant to this discussion.

-----

1 point by shader 5606 days ago | link

It looks like sml supports both '@ based attributes and also a form like

  (tag attr1 "value" attr2 "value"
    (bodyless-tag)
    (tag-w/body "body"))
It looks like it's function based and works on simple lists, so it would probably be conducive to the quasiquote form of escaping to arc. Anything seem to be missing from sml.arc that you wanted in your new version? Personally I think the interface could use some work, but that's about it.

-----

1 point by shader 5606 days ago | link

Hmm. I'll have to see if I can find it elsewhere. I guess that w/html must have been a macro that bent quotes to its own purpose, whereas marcup or your 'tohtml merely take lists as input.

sml.arc sounds familiar; I vaguely remember someone else going through a discussion similar to ours, in which SXML was also mentioned.

-----

1 point by akkartik 5589 days ago | link

I shouldn't get any credit for jazzdev's sml.arc: http://github.com/nex3/arc/commits/master/lib/sml.arc

-----

1 point by evanrmurphy 5588 days ago | link

Thanks for clarifying the authorship.

-----

3 points by shader 5606 days ago | link | parent | on: Suggestion: how to improve arc.

So your real question is why dots don't work in quasiquote, and what should be done to fix them. That's a question that we can relate to a lot better than what we originally thought was "I don't like dots"

-----

5 points by shader 5607 days ago | link | parent | on: Suggestion: how to improve arc.

Not sure exactly what you're going for with the "function ignored by the compiler" Maybe a few more examples would be more helpful?

In general, when you have things that you want to improve about arc, I would recommend one of two things:

1) If your change is merely syntactical, or is trying to get arc to use a different style of programming (oop, etc.) try doing things the arc way for a while, and see if you can't learn to appreciate it the way it is. It's quite possible that after a while you'll learn to prefer the traditional lisp/arc method.

2) If you're writing on the forum about changes that you'd like to see made to arc, try implementing them and submitting them first. This will allow the community to experiment with your ideas and give better criticism, as well as give you a greater understanding of why things are the way they are, and how hard it might be to change them.

This is an "open source" community. That means you have just as much opportunity to implement your desired feature as everyone else, but a better understanding of it and a lot more interest in getting it done. If you don't feel like implementing your feature, odds are no one else will either.

-----

2 points by fallintothis 5606 days ago | link

Maybe a few more examples would be more helpful?

Seconded. In this example, what's the problem with metadata-manipulating macros? Seems you should expand them into something that sets the metadata.

  (mac declare (name prop)
    `(= (metadata* ',name) ,prop))
What does ignoring accomplish, here or elsewhere? If you don't want a return value, just return nil -- though, almost always, having one won't hurt.

-----

1 point by ylando 5606 days ago | link

Suppose we want to declare a name inside a function We must use it outside of the function definition For example:

  (declare int_value int
  (def myfunc (...) ...
     (let int_value 3 ... )))

-----

2 points by fallintothis 5606 days ago | link

I still don't follow. A) Why do we need "ignores" here? B) Why would we need to use the declaration outside of the definition? Expressions can be sequenced. I.e., wouldn't you do something like this?

  (def f (x y)
    (let i 3
      (declare integer i)      ; this is evaluated and sets metadata...
      (something-with x y i))) ; ...but THIS is the value that gets returned
Similarly,

  (def foo (bar)
    (let baz 10
      (prn "hello") ; evaluates and returns the string "hello"
      (+ bar baz))) ; evaluates and returns bar + 10

  arc> (foo 5) ; prints hello and returns 15
  hello
  15

-----

1 point by ylando 5606 days ago | link

In the example above you waste run time on declaring i as integer.

Suppose we want to declare the value for a region of code; like a let statement. We can do it in the following way:

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

  (mac undeclare (name oldprop) 
    (= (metadata* obj) oldprop)
    'temporary*)
If we put it in a function body, we still waste time.

-----

1 point by zck 5606 days ago | link

I think fallintothis declared i as an integer because ey was trying to translate your code, which declares int_value as an integer.

So the 'temporary call serves to tell the 'do in 'declare not to return the value from 'undeclare, but instead to return the value from the (= temporary* (do ,@body)) line?

This seems a lot more complicated than simply saving the value in a 'let or using do1.

-----

2 points by fallintothis 5606 days ago | link

This seems a lot more complicated than simply saving the value in a 'let or using do1.

There's also a typo:

  (mac undeclare (name oldprop)
    (= (metadata* name) oldprop)    ; was (= (metadata* obj) oldprop)
    'temporary*)
Even fixing that, the metadata-setting happens at macroexpansion time, so you get

  arc> (def f (x) (declare x integer (prn "metadata*: " metadata*) (+ x 5)))
  #<procedure: f>
  arc> metadata*
  #hash()
  arc> (f 5)
  metadata*: #hash()
  10
  arc> metadata*
  #hash()
At no point before, after, or in the body is the metadata actually in the hash table. It was just there for a brief pause between the macroexpansions of declare and undeclare.

In all, I would've written it

  (mac declare (name prop . body)
    `(after (do (= (metadata* ',name) ',prop)
                ,@body)
            (= (metadata* ',name) ,(metadata* name))))
But the last line shows we just wipe any declaration we made, so a global metadata table gets messy, unless we make the declarations themselves global (i.e., get rid of body).

-----

4 points by rocketnia 5606 days ago | link

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 5603 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 5603 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 5602 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 5601 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.

-----

More