... initially, it would seem that you can distinguish the two by whether there's a ( following the with, but you might get into trouble:
(let (x y) mylist
(pr x y)
where let is followed by a (. mmm. I'm a still quite unfamiliar with arc or lisp. Can anyone give an example in which interchanging the "let" for a "with" or visa versa changes the meaning of the function?
You yourself gave an example. The fact that Arc allows destructuring (that is, writing (let (a b) lst ...)) means that the presence of a list is not an adequate indicator of whether you're letting or withing. And without that, how do you know when you're done defining variables? If you don't parenthesize them, they could go on forever. The only other option is to remove the implicit do in let/with; that way, only the last statement would be run, and the first n would be variable bindings; to run more than one, you would use do.
That said, it might be good to remove the implicit 'do anyways, since as pg has said, an explicit 'do highlights non-functional code. Combining 'let and 'with would just be a convenient side effect.
P.S. If I am not mistaken I think this would also allow you to do destructuring as well...
This is actually fairly simple to write (first defining butlast for convenience):
(def butlast (seq)
" Returns every element of `seq' but the last one.
See also [[last]] [[cut]] "
(cut seq 0 -1))
(mac letn parms
" Simultaneously ssigns the given (unparenthesized) local variables in the
one-statement body.
See also [[let]] [[with]] [[letns]]"
`(with ,(butlast parms) ,(last parms)))
(mac letns parms
" Sequentially assigns the given (unparenthesized) local variables in the
one-statement body.
See also [[let]] [[with]] [[letn]]"
`(withs ,(butlast parms) ,(last parms)))
Then letn is like with, but unparenthesized, and letns is like withs, but unparenthesized. (letn = "let n variables".) And yes, destructuring works.
Heck no. We can do this ourselves. Remember, the textual transformation to transform let's is just that: a textual translation. It should be possible to create an automated translation tool (based off raymyers' treeparse) that will handle this for us.
Let the old version of 'let be Arc2Let, and the proposed new let be Arc2.7Let. Let the old version of 'with and 'withs be Arc2With and Arc2Withs, respectively. We need to determine if each Arc2Let in the source is composed of a single expression in the body. If it is, we leave it as-is. If it isn't, we simply replace it with Arc2.7As.
For each Arc2With we determine if the body is composed of a single expression. If it is, we replace it with Arc2.7Let, removing the parens around the Arc2With bindings. If it isn't, we leave it as-is. Ditto for Arc2Withs, replacing it with Arc2.7Lets.
We define an expression simply as a sequence of whitespace, base-expression, and whitespace. We define whitespace as being either a comment (either #||# or ;) or ordinary whitespace.
A base-expression is simply a symbol, a number, a character, a string, a quote-expression, a comma and comma-at expression, or a list. A quote-expression is simply the ' quote or ` backquote character followed by maybe whitespace, followed by an expression; comma and comma-at are defined similarly. A list is composed of an opening parenthesis followed by many expressions, followed by a closing parens.
We can determine if a 'let form has several expressions by defining two variants of a 'let form. An Arc2Let is composed of ( <maybe whitespace> let <whitespace> <expression> <expression> <expression> [many <expression>]), and that we have to transform to Arc2.7As (by filtering out the let expression using treeparse 'filt). An Arc2.7LetCompatible is composed of just (let <expression> <expression> <expression>), which we do not transform.
----
Of course, this does represent a veritable fork of the Arc code ^^.
I would leave with and withs alone, so that we have the option of the implicit do (also because it makes it easier to implement given/Anarki-let :P). And why not use a code-tree-walker if we want to do this—isn't that the point of Lisp?
Right, comments. Just a little important, aren't they? :P
You raise a good point... it's the same number of parentheses either way. But in that case, why not just have let and lets (as given(s)), and be done with it?
Edit: as an aside, given that pg has said that he'll modify Arc as if there's nobody else programming in it, and that he does not appear to be using Anarki, eventually when Arc3 does come around, it is very possible that Anarki will be incompatible with Arc3. We may very well need to build a converter program in the future to transform Arc2-base Anarki to Arc3-base Anarki, so my abstract nonsense may very well be necessary in the future.
I've been programming with given(s) for a little while now, and I really like it. Can't say why I'm so vehement, but it's definitely a Good Thing™. Thank you for bringing this up again (and a "thank you" to aidenn0, if he/she is still reading these fora, for suggesting this in the first place).
An interesting bit about 'givens is that it makes functional programming in an imperative style almost seamless:
(givens f (car n)
v f!v
_ (prn v) ; v isn't being set properly in some cases for some reason...
l (combinatorics f v)
_ (prn l) ; debugprint
(is l 'undef))
The difference between given and let/with is that you cannot have more than one statement in the body of the given. For instance:
arc> (given (a b) (list 1 2)
(prn "Here")
(pr a b))
Error: "Can't understand fn arg list \"Here\""
What's happening here is that given is trying to bind (prn "Here") to (pr a b), but (naturally) can't bind a string; it takes the first n args, where n is the largest even number less than or equal to the number of arguments provided, and interprets them as variables. You must, therefore, write
arc> (given (a b) (list 1 2)
(do
(prn "Here")
(pr a b))
Here
121
.
Also, I highly recommend switching to Anarki. It's got bugfixes and enhancements galore (and even runs on the newest version of mzscheme).
It's the only "drawback", if such it is. I feel that since you need extra parentheses for either the body or the variables, it's better to wrap the body in a do, since that's less common.
; in fact, that's often what I do. But being able to write snippets of Scheme can be important, if you need to work with things (for instance, datatypes like the boolean) which don't exist in Arc.
defcall is pretty simple to use. The syntax is the same as that of def, except instead of a function name, you provide the type of the object. The function receives both the objects and its "arguments". E.g.
arc> (defcall sym (self n)
(repeat n (prn self))
#<procedure>
arc> ('a 3)
a
a
a
nil
.
What does your current database look like? What relationships are you hoping to add?
I assume you're using deftem to define your database objects. I was thinking that it would helpful to have a version of deftem that automatically created defops for adding, updating, and deleting objects from a database (similar to Rails scaffolding).
I know someone made scaffolding work earlier, but I don't know exactly how they did it.
Anyway, ideally with templates -- in my case, one for posts and one for tags -- you'd be able to make use of this relation in a functional way with no real performance issues.
I was the one who created the scaffolding system- It does, indeed, generate the code to add/update/etc from a database. I've continued to expand the system on my own, but since there wasn't much interest in the arc forum I decided not to continue checking code into anarki for now, but may again in the future- So right now it is strictly ver 0.01, though I'm surprised others seem to manage without a scaffolding system...
As for the issue of one-many and many-many, I guess I would suggest that in a one-to-many situation I would try and store the "many" as a child field in the "one", not use two separate tables if you can get away with it (one of the advantages of a non-RDBMS is that this design is possible)
As for many-many, I would probably have two tables, then have an extra table that just maps keys to keys for the two tables. Basically, just like an RDBMS association table. (or maybe even a bidirectional table, if you need to go "both ways")
If you want to know the "official" way to store data in different relationships in a simple, purely functional, memory resident database, I'd look at HApps-ixset. This is philisophically closely aligned to what you'd need in arc and is designed by some super smart guys. Unfortunately, their documentation is wanting or I'd point you to a good link that describes how to use it.
I've been thinking it might be possible to make these mappings implicit. Imagine you had a version of deftem (I'll call it defitem) that inspected the fields in your templates:
(defitem post
id nil
title nil
text nil
tags nil)
(defitem tag
id nil
text nil
post nil)
defitem would see that post has a relationship with tag and tag has a relationship with post by looking at the names of the fields in each template. Since the post field in tag is singular and the tags field in post in plural, it would know that there is a one-to-many relationship between post and tag. Then defitem could create any necessary accessor methods.
Anyways, that's what I've been attempting recently.
Arc seems pretty open to me. There's nothing stopping people from creating countless useful libraries. I'm guessing that many people have turned away from Arc after seeing the dirth of libraries. Paradoxically, that's one of the things that attracts me to Arc. There are many opportunities to make an early impact within the Arc community.
If all you want is to add two numbers together, a function will be sufficient:
(def meta (x y)
(+ x y))
Macros are usually only used when trying to accomplish something that cant be done with a regular function.
If you want to accept an arbitrary number of arguments, the following would work:
(def meta (x . y)
(apply + x y))
or:
(def meta xs
(apply + xs))
This could also be accomplished with a macro:
(mac meta xs
`(+ ,@xs))
In your original definition of meta, arc thinks that y is a list since it follows the dot syntax (x . y) It then throws an error when it evaluates (+ 1 (2)) because it doesn't know how to add a number to a list.
It looks like pr prints out all its arguments and then returns its first argument. You can safely ignore the final value. If pr was used in a web page to print out some text, the return value would never be seen.
As far as the @ symbol, the following code causes an error:
arc> (mac meta xs
`(+ ,xs))
*** redefining meta
#3(tagged mac #<procedure>)
arc> (meta 1 2)
Error: "Function call on inappropriate object 1 (2)"
xs will have a type of 'cons in this situation. Which means it sees it as (element . list). So for your example it'll see it as 3 (3 4 5 66 67). It just happens that pr deals with cons types well.
It looks like the final left paren in hyfac is misplaced. It needs to be before the call to fac. Also, unless you explicity return y, hyfac will just return nil.
(def hyfac (n)
(let y 1
(for x 1 (+ n 1)
(= y (* y (fac n))))
y))
To get arc running on Windows I downloaded DrScheme (http://download.plt-scheme.org/drscheme/), which includes MzScheme. After installing DrScheme launch the application. When first using DrScheme the IDE will ask you to select a language in the lower left hand corner. I chose PLT -> Textual (MzScheme, includes R5RS). Then go to File -> Open and navigate to as.scm in your arc directory (it doesn't matter where the arc files are located on your system). Click Run at the top of the IDE and the Arc prompt should start up.
Am I correct in thinking that asv only supports one-way asynchronous communication from the client to the server? If so, does anyone have any ideas for supporting two-way async?
Actually asv doesn't even support that. It has jfnurl* which is called an asynchronous request, but really it's just a normal request with the result thrown away. The client still blocks for the duration of the request, so nothing is really asynchronous. I suspect asynchronous communication is a not-yet-implemented feature.
But to answer your question, it depends what you mean by two-way async. HTTP only supports requests from the client to the server, so you need to use something like polling, Ajax, HTTP server push, or Comet (see http://en.wikipedia.org/wiki/Comet_%28programming%29). I don't think there's anything in srv.arc that would prevent a persistent server connection, if threadlife* is increased from 30 seconds. (A thread per persistent connection would eventually have scaling issued, though, I think.)
I took a closer look at using Ajax with Arc. It turns out to be pretty easy, thanks to script.aculo.us. I've written details at http://arcfn.com/2008/04/ajax-and-arc.html - please let me know if it works for you or not.
I've substantially changed my example, so it now fetches country data using Ajax.
The biggest problem with using Ajax is that the Arc web server doesn't support .js files, which is a big oversight for a web-targeted language. Consider this a bug report suggesting support for .js static files. (Really the design should allow arbitrary static files with arbitrary mime-types, rather than hard-coding the list.)
If anyone has Arc running on a public web server and wants to run the Ajax example, let me know and I'll add a link to your site from my page. (My hosting isn't suitable for running Arc.)
Actually, the Anarki supports exactly what you want with static files: a root directory for static files, and a table mapping extensions to mime types for them.
And there's a typo on your page: you don't close the code tag around "/getcontents?field=population&name=value", so the rest of the page is in monospaced font.
That said, your site is consistently fantastic, and I find it amazingly useful. Please keep it up!