Have you looked at Termite (that is, Gambit)? It seems to support continuations well - continuations are even serializable (along with ports, threads, etc) - and I think concurrency is handled exceptionally elegantly (built-in message-passing a la Erlang).
I never got many chances to use such exotic features, but I believe the combination of message passing and serializable continuations would allow you to do fun stuff like easily transfer code execution between different computers.
My limited experience suggested it was fast. It's also compilable to C. I suspect tail calls are properly handled - doesn't seem like something Feeley would let slide. I'm not sure about reliability.
I stopped using it because of lack of documentation and poor library support.
I'm not proposing hacking existing functions. Basically everything should be able to be maintained by running a diff between the 2 arc.arcs and pasting the extra functions in the Anarki version into pg's new arc.arc. What difficulties did you encounter last time?
Hm. Anarki calls them w/stdoutfile and w/stdinfile, but wouldn't tofile and fromfile be more consistent with tostring and fromstring (and shorter, besides)? Then there's the whole appending business. Can't really give an optional parameter to tofile like outfile has, and toappendfile runs together horribly. What about just appendfile?
Then, using readline instead of readfile so that it (1) doesn't try to parse things as s-exprs and (2) doesn't read the entire file for no good reason, I'd envision it thus:
I'm not sure about the appendfile--given what infile and outfile do, it sounds like a procedure that creates an output-port that appends to a file. Maybe to-appendfile, appendtofile, appendingfile, tofile/append... Alternatively, we could make keyword arguments happen in Arc, and then you would just throw ":append t" or something inside the call to tofile. That would also allow for further extension with, e.g., an :if-exists argument.
How about 'tolog? Are files opened for appending for other reasons, in practice? This would also keep with the to-means-output, from-means-input pattern.
I'd try to err on the side of generality. And I'm not quite as concerned about to:output / from:input, if the names are still "clear enough".
As to waterhouse's suggestions, I had considered those names. I suppose if you read appendfile as a noun instead of a verb-and-noun, it's confusing (though infile and outfile don't really have the same problem, so it's not the train of thought my brain follows). It's hard modifying a name like tofile with a long word like append. We already have two words in tofile, so adding a third without hyphenation is stretching it, and adding hyphens breaks the flow with the other names (fromfile, tostring, etc.). We could go for something shorter, like addtofile, which delineates itself well without hyphens because each word is one syllable. If we can't avoid hyphens, using / instead (e.g., tofile/a or tofile/append) flows better, but isn't that great.
Another name that occurred to me -- and is probably my favorite so far -- is ontofile, which is still simple enough to not need hyphens, communicates intent (appending something onto a file), and worms the word to in there, painting it with the to:output / from:input correlation. Thoughts?
Another name that occurred to me -- and is probably my favorite so far -- is ontofile, which is still simple enough to not need hyphens, communicates intent (appending something onto a file), and worms the word to in there, painting it with the to:output / from:input correlation. Thoughts?
+1! ontofile is a great name, in my opinion, for all the reasons you listed.
I searched for a good portmanteau in the vein of mappend, but I don't think there is one. fappend? Sounds like frappuchino. filepend is decent, but I think I prefer ontofile.
Yes and yes. With pg's code, I kept having to make ugly hacks to things like respond to be able to do what I wanted. It was hard to modify, hard to maintain, and hard to debug. IMO, palsecam's code is much more flexible and much better written. I highly recommend it.
So throw serves to "point back" to the current continuation, and optionally continues with a return value. (This seems to be the behavior of a simple (ccc (throw) ...) without the let; I'm not sure why it's defined this way.) The above loop returns 5 -- the continuation captured by ccc is outside of the loop, so its action is to return whatever value we say the while expression returns and continue evaluating anything after it.
This way, Arc gives you a decorator for return values. You can use this pattern to decorate any portion of your loop, to give different effects. Outside of the loop, it's like a break. Inside of the loop, it's like a continue due to how while is expanded.
As you can see, the continuation is captured around the body, but the test properly resides outside of the body, so it'll still be executed even if you continue (because, again, the default continuation is to keep on chuggin' along).
You could have a while macro encapsulate these (similar to catch) so you don't have to write
(point break
(while test
(point continue
body)))
I've been trying to think of good names for such a loop. The most descriptive words are long (e.g., continuable-while, breakable-while), but we usually recognize "esc" as "escape", so it's a short yet descriptive option. Something like
To make code show up here properly, put two spaces before each line of code and paste it here. As in:
;I used this function to add spaces so I could put it here!
(def add-spaces (xt)
(no:map [prn " " _] lines.xt))
This assumes you have it indented already. If you don't, find a text editor that indents Lisp code for you (I recommend DrRacket). The 'ppr function works reasonably well, too.
ccc is certainly way to go, but just in case: mzscheme does not use continuation passing style so the ccc can work much much slower than just a function call because it copies the stack.
Actually I didn't do the profiling so maybe there is nothing to worry about.
Ah, that helps understand ccc. I've been mulling ccc for months without having a handle on it. But seeing a simple solution to a simple problem I can relate to helps immeasurably.
Thanks, but next in an xloop doesn't really work as a substitute, right? The code after a (next) still gets executed after the recursion completes, whereas with a continue, the rest of the branch isn't executed. I really need the latter.
(I wrote this response before I read some of the more recent comments, so it'll end up duplicating information, but I'm posting it anyway 'cause of the example utilities.)
In that case, I typically use 'catch or 'point (which indeed use continuations). If you want a loop with the ability to either break or continue, you can put a 'point on the outside and another 'point on the inside.
Here's a half-effort to abstract this away. I don't know how useful it'll be, but it might be the start of something better, so everyone, feel free to use it for anything without credit. ^_^
(mac w/breaks (break next loop-header . body)
(w/uniq g-breakpoint
`(point ,g-breakpoint
(let ,break (fn ((o val)) (,g-breakpoint val))
(,@loop-header
(point ,next
,@body))))))
(mac forever body
`(while t ,@body))
(mac bforever body
`(w/breaks break next (forever) ,@body))
(mac bfor (var start end . body)
`(w/breaks break next (for ,var ,start ,end) ,@body))
; What a name.
(mac beach (var coll . body)
`(w/breaks break next (each ,var ,coll) ,@body))
; Turn any loop into a breakable one. Example usage:
;
; (b-:until (all has-come-home cows) :
; (tip rand-elt.cows)
; (unless whales
; (next))
; (actually-beach rand-elt.whales)
; (when cops
; (prn "Uh, oops?")
; (break)))
;
(mac b- (loop)
(let (header (_ . body)) (split loop (pos ': loop))
`(w/breaks break next ,header ,@body)))
(Clearly, this wouldn't mix very well with 'xloop; since an 'xloop doesn't loop unless you make it loop, a "continue" continuation wouldn't really make any sense.)
I use some i18n in my programs, a key decision I think you'll have to make is whether translation should be done at compile-time or dynamically. I went the former route, but I often find myself wishing my strings were translated dynamically.
I use a global called locale* and have a macro which translates strings based on it. I'd be happy to work with you and the community to agree on something we all think works well and put it in the github repo.
I don't think the cost of dynamic lookup will be very high, at least in news.arc there isn't that much text. I intend to use a function that looks into a table:
(prn (i18n 117))
I think numbers over pseudo-text-symbols will fit with arc's keep-it-brief style.
I don't like the numeric setup - I find it makes the code hard to read. Most of the other i18n libs I've seen use English in the code and then a mapping between English and other languages in a separate file. I think that approach makes more sense. When I'm skimming code, I'd rather read (i18n "Add Comment") than (i18n 143).
Please feel free to use arcscript. I only dumped that file into the repo because I had it lying around and thought someone might have use for it. You got around to completing a nice functional JS compiler implementation before I did and I'm glad you did. Feel free to upload on top of my file :)
I have looked at parenscript and even started an arcscript which is totally non-functional - I was just translating it to Arc as I went as a way to understand the original codebase. I never finished it, but I'll post what I have on github and maybe we can collaborate.