Arc Forumnew | comments | leaders | submit | kens1's commentslogin
3 points by kens1 6308 days ago | link | parent | on: Will Arc ever be as fast as CL?

I don't get it. There's the whole stack copying for call/cc, so call/cc is much more expensive.

(I read the "Lambda the ultimate GOTO" paper you referenced earlier; it's about goto vs structured programming, not call/cc. As an aside, it's very interesting to reflect on just how controversial structured programming was.)

-----

4 points by soegaard 6308 days ago | link

Implementing call/cc efficiently has been well-reasearched in the Scheme community. For a very well-written account of a non-stack-copying implementation see

R. Kent Dybvig. "Three Implementation Models for Scheme". PhD. Thesis. http://www.cs.indiana.edu/~dyb/papers/3imp.pdf

Then continue at ReadScheme at "Compiler Technology/Implementation Techniques and Optimization" to see further developments (Look especially for Clinger's papers).

http://library.readscheme.org/page8.html

-----

2 points by almkglor 6308 days ago | link

Who said anything about copying stack? For that matter - who said local variables should be kept in the stack anyway?

-----

1 point by kens1 6308 days ago | link

In MIT Scheme, the stack gets copied; at least that's what I was told last week. Whether or not you use a stack, the state will need to be copied.

-----

1 point by almkglor 6308 days ago | link

In a function call, the state (the current computation being done) is saved anyway, and therefore "copied" if that is your preferred term. So ideally, call/cc should have the same overhead as an ordinary function call; the only difference is that in call/cc the continuation state is the value given to the function, while in a function call it's just one of the values given to the function.

Note however that much of the theoretical analyses of call/cc make a basic assumption of a "spaghetti stack", which would mean that partially unwound stacks would be saved implicitly as long as any continuation exists which refers to that stack, and all stacks themselves are subject to garbage collection. Most machines don't actually have a spaghetti stack and can't make a spaghetti stack anyway ^^. That said a spaghetti stack could be implemented as a simple list, with push == cons and pop = cdr.

Alternatively store the local variables on a garbage-collected heap, and include a reference to the local variables with the continuation/return address (you'll probably need to save the pointer-to-local-variables anyway, since the target function is likely to use that pointer for its own locals). Again, no additional overhead over plain function calls, except perhaps to restructure the return address and the pointer-to-local-variables.

Don't know about MIT Scheme, but if I were to implement call/cc on stock hardware and compiling down to machine language that's what I'd do ^^

-----

3 points by kens1 6308 days ago | link

I'm still totally not understanding your claim that call/cc should have the same overhead as an ordinary function call.

I read the Clinger "Implementation Strategies for Continuations" paper and they found call/cc about 10 times slower than function calls on the tak/ctak tests. I tried those tests on PLT Scheme and the overhead I saw is even worse: .7 seconds with function calls vs 51.8 seconds with continuations on (tak 24 16 8).

Clinger says about the stack strategy: "When a continuation is captured, however, a copy of the entire stack is made and stored in the heap. ... Variations on the stack strategy are used by most implementations of Scheme and Smalltalk-80."

-----

3 points by almkglor 6307 days ago | link

Components of function call: (1) put arguments somewhere (2) put return address somewhere (3) jump to function.

Components of call/cc: (1) put return address as argument somewhere (2) put return address somewhere (3) jump to function.

That said, continuations generally assume that "put X somewhere" means somewhere != stack. Yes, even return addresses are not intended to be on the stack when using continuations. The main problem is when compiling down to C, which always assumes that somewhere == stack. If you're compiling down to machine language where you have access to everything, then you can just ignore the stack, but not in C, which inherently expects the stack.

-----

1 point by kens1 6309 days ago | link | parent | on: destructuring the quotation symbol

I took a look at arc.arc, and I didn't see any macros there that would be helped by destructuring quotation. I did notice that the macros: w/stdin, w/stdout, thread, atomic solely exist to wrap body code in a lambda (fn) expression. Maybe that sort of wrapping would be useful to add to defq?

-----

1 point by drcode 6308 days ago | link

Yes, most of the axiomatic stuff in arc.arc probably would not benefit from this I think. I can see a couple, such as "deftem", that could probably make use of this.

-----

2 points by kens1 6311 days ago | link | parent | on: Arc challenge: 8 Queens Problem

Is nil! an Anarki thing? (wipe m) is the Arc expression to set m to nil. (And (assert m) sets m to t. Assert tops my list of confusingly named functions.)

-----

2 points by nex3 6311 days ago | link

No, nil! was just the old name for wipe.

-----

2 points by kens1 6311 days ago | link | parent | on: How to implement a no-side-effects macro?

If you want the gory details of places, see my recent document: http://arcfn.com/doc/setforms.html

-----

1 point by lacker 6311 days ago | link

Wow... that is gory. :-/

It seems like the most plausible way to keep scar/scdr/sref from mutating variables outside the no-side-effects scope is to keep a table of the variables they are allowed to operate on, which is basically anything the user created with cons or table inside the no-side-effects scope. This should invalidate code like

(= a (table))

(no-side-effects (= b a) (= (b "key") "value"))

Is there any more natural way to track this than keeping a table keyed by symbol?

-----

3 points by eds 6311 days ago | link

This is probably a horribly inefficient way to implement this... but couldn't you just copy all the variables before executing the body?

Assuming

  (= a (table 'foo 'bar))
then a line like this

  (no-side-effects (= a!foo 'baz) a)
might be converted to something roughly like this

  (let a (copy a)
    (= a!foo 'baz)
    a)
a is unchanged after evaluation because the let made a deep copy that overshadowed the global value of a.

You would still have to think about constructs like def and mac, but at least this deals with shared structure of lists and tables.

Maybe something like http://arclanguage.org/item?id=3572 ?

-----

3 points by kens1 6312 days ago | link | parent | on: How to implement a no-side-effects macro?

I think you're looking for Java, and its security manager :-)

MzScheme's namespaces (http://download.plt-scheme.org/doc/mzscheme/mzscheme-Z-H-8.h...) may help you with this, since you can have a separate namespace for each "sandbox", and the variables won't collide.

I guess you could also do this with a macro that replaces all the symbols by gensyms, so inside no-side-effects, foo is really a unique variable. But that seems like a pain to implement.

As an aside, watch out for denial-of-service attacks in untrusted code: e.g. code that goes into an infinite loop or infinite memory allocation. Depending on what you're doing, that can be a big problem, or not.

-----

2 points by lacker 6312 days ago | link

"Use Java" is not the answer I was hoping for. ;-)

This seems like such a simple request - I can express it in a few sentences - that it should be at least not extremely difficult to implement in the ideal programming language. So I hope it can be done in Arc, and if not, hopefully this is a use case that can be taken into account while figuring out how to handle arc modules/namespaces/whatever.

Anyways. I thought about replacing symbols by gensyms, but at what point would I do that? If I just check all symbols in the code I will miss things like

(eval `(= ,(sym "foo") 2))

For denial of service, I was thinking about something like (reval n code) would run the code but only allow up to n function calls. Seems like this would require writing eval in Arc then modifying. Is this similar to what you were suggesting by a replacing-symbols-by-gensyms macro?

-----

1 point by kennytilton 6312 days ago | link

"This seems like such a simple request - I can express it in a few sentences"

Awesome. I want to time travel. That's just one sentence. :)

"it should be at least not extremely difficult to implement in the ideal programming language"

Cue the asbestos! No one said Arc was intended to be some abstract ideal satisfying all few-sentence specifications, and as per the Java crack, who says that the ideal language is idiot-proof or attack-proof? To the contrary, the Design Imperatives I have seen trust the programmer to be good and are not hoping to be able to run virus attacks imperviously.

As for your question, it is a hard problem and one reason I think we do not have a Lisp plug-in for browsers.

-----

4 points by lacker 6312 days ago | link

I don't mean to start a flame war - I am certainly not a big Java or JavaScript fan ;-)

I don't want to make the language idiot-proof. I acknowledge this is a hard, rather "meta" thing and I was hoping Arc would be powerful enough to do this.

So, regardless of whether "the ideal language would have it", you agree this would be very useful; it would let us have an Arc plug-in for browsers for example. Or make a site where you could make your own Arc site by entering code and the main servers would run it restrictedly. Arc is trying to be native to the web, and allowing restricted execution is a very webby thing to do.

Anyway, I will still try to do this. ;-)

-----

2 points by kennytilton 6312 days ago | link

"I was hoping Arc would be powerful enough to do this."

OK, asbestos did not work, try the foam!

What you might be missing is that power makes attacks easier, not harder. As I suggested, part of that power is reflection so you have a fighting chance, my concern is that once you have blocked all the exits there will be no way to get in. Whatever that means.

"you agree this would be very useful"

I do? Wow. Actually, I do not know much about security,tho I might have to learn soon. My guess is that probably the best way to go is not to cripple the plugin, rather to allow only registered, vetted, digitally signed code to run. ie, the plugin looks for a digital certificate before launching.

Tilton's Law: Solve the right problem. What is the problem? Losers posting evil code. Solution? Don't run just anyone's code.

-----

3 points by sacado 6312 days ago | link

"I think we do not have a Lisp plug-in for browsers"

Well, we have JavaScript, and it is not really safer by design than Lisp (they are quite close, too). But JavaScript has a security manager, quite restrictive sometimes. And look at rebol : that's also a close relative to Lisp and it's got a cool security manager.

Well, they mainly prevent you from reading/writing the host filesystem or from connecting to undesired remote servers.

Lacker, this might not be as "secure" as Java's model, and not exactly what you were asking as it does not prevent you from overwriting another's code, but it is obviously enough to run untrusted code on one's machine. And to implement it, you only need to overwrite the dedicated axioms in ac.scm.

-----

1 point by kennytilton 6312 days ago | link

"Well, we have JavaScript,"

Then there was that other ILC where the speaker argued we Lispers should rejoice because Javascript was a Lisp and was in all the browsers. Make sure there are no children in the room and I'll tell you what happened next.

-----

1 point by sacado 6312 days ago | link

Compared to Java (i.e., seen from far away), it is. Well, of course, code isn't also data in JavaScript :)

-----

1 point by kennytilton 6312 days ago | link

Many agree. Here is a blog entry on the ILC guy I mentioned:

  http://bc.tech.coop/blog/030920.html
Looks I'll be tearing into ActionScript shortly, I'll let you know. :)

-----


You had me worried, but I'm pretty sure there's absolutely no problem with using strings as the keys for tables.

The MzScheme documentation says: make-hash-table ... 'equal -- creates a hash table that compares keys using equal? instead of eq? (needed, for example, when using strings as keys).

Checking ac.scm, sure enough:

  (xdef 'table (lambda () (make-hash-table 'equal))
Likewise, the "is" operation in Arc uses MzScheme's string=? . (That's a statement, not a question :-) So string comparison works, although in O(n) time.

Net net: strings are okay for comparison and table keys in Arc.

-----

2 points by absz 6313 days ago | link

I wasn't saying that they weren't usable, just that they were, in fact, slower; that's what you observed. Symbol comparison is O(1) time, whereas string comparison is O(n) time. That's all.

-----

4 points by kens1 6314 days ago | link | parent | on: How do I Run a Program?

To run Arc from a file, I think what you're looking for is the script at http://arclanguage.org/item?id=1424

-----

6 points by kens1 6314 days ago | link | parent | on: Issues Regarding Lisp Adoption

In my experience, the meta-issue is that there are multiple substantial barriers to Lisp adoption, and an uncertain payoff, leading to the question, "Is this really the best use of my time?"

The first substantial barrier is Emacs. Before learning Lisp, first you must learn Emacs. I've tried several times, but keep deciding it's not worth the effort. Imagine for an instant that in order to use Ruby, you need to use some strange Japanese editor, but it's really not bad once you get used to the cryptic commands and rebind your keyboard so it is usable. Do you think this might hamper the adoption of Ruby?

Next, the IDE. I'm willing to put up with Slime's 1980's styling, but I keep ending up in mysterious inferior modes that don't seem to be documented. After reading through Slime documentation, it seems I need to understand Emacs's Lisp modes first.

Then, the REPL. Sure, it's nice to be able to interact. But sometimes I need to write a self-contained script that can take part in the whole Unix environment: things like being part of a pipeline, running as a cron job, running through CGI, running as a command. Python makes this trivial; Lisp makes this difficult or impossible.

Then there's the payoff. Will Lisp actually help me solve any of my problems? That's still extremely unclear. Perl or Python are great for random problems I have, such as "Fetch a web page, pull stuff out with regular expressions, and convert it from iso-8859-1 to UTF-8" or "Analyze a pcap dump file". This is where Lisp runs into the infamous library issues. The problems Lisp solves seem to not be the problems I want to solve.

The issue of a dialect/implementation is somewhat vexing: try reading SICP and Practical Common Lisp at the same time, and discovering that everything is different. Also, the expectation that whatever implementation you pick will be the wrong one for the libraries you want is a bit scary. But overall, I'd say this isn't a fundamental barrier.

The above is meant as an honest answer to your question; I'm not interested in starting a flame war.

I am pleased with DrScheme, by the way.

-----

7 points by jimbokun 6314 days ago | link

"But sometimes I need to write a self-contained script that can take part in the whole Unix environment: things like being part of a pipeline, running as a cron job, running through CGI, running as a command. Python makes this trivial; Lisp makes this difficult or impossible."

This is hugely under-estimated as a reason for lack of Lisp adoption. I would put this way ahead of lack of IDEs.

-----

2 points by lojic 6314 days ago | link

"The first substantial barrier is Emacs. Before learning Lisp, first you must learn Emacs. I've tried several times, but keep deciding it's not worth the effort."

First of all, I don't think it's accurate to say that you must learn Emacs before learning Lisp. Other editors such as vi or IDEs such as ACL & LispWorks are used successfully.

On the other hand, after using IDEs for over a decade, I switched to vim for a couple of years and more recently switched to Emacs. Get the "Learning GNU Emacs" book and it will be trivial to pick up Emacs.

-----


The problem I ran into today was:

  arc> (apply or '(nil t nil))
  Error: "Function call on inappropriate object #3(tagged mac #<procedure>) (nil t nil)"
I assume that first-class macros would let me do this.

-----


I'd like improvements in basic usability. This includes filling in missing functionality (e.g. trig, socket connections, regular expressions) and/or an escape to Scheme to do these. Also non-brokenness on Linux, Windows, etc. Also ability to simply make a non-REPL Arc script. Picking up the Anarki stable fixes would probably cover most of this.

On the trivial side: w/bars must die.

One question: why is currying so popular? I don't see the point, so I guess I'm in blub-land with respect to currying.

-----

7 points by nex3 6315 days ago | link

The post by raymyers (http://www.arclanguage.org/item?id=3997) gives some very cool examples of the power of bracket-style currying. In addition to cutting down the number of tokens in the common [foo bar _] case of bracket-notation, it allows much nicer wrapping of variadic functions - or just functions for which you want to leave more than one argument open. Compare [* 2] to (fn args (apply * 2 args)), for instance.

-----

More