What's the most important sentence, something like "don't use arc 3.1, it has a bug, use this stable branch instead"? It's a wiki, please feel free to make changes to it. It might be easier to discuss this using actual changes.
Update: Ok, I've taken a stab at making the biggest gotcha more clear.
I don't see how that issue would stop you from using Anarki. And it appears news.arc was modified to accommodate the change.
I have to say, I don't like that change in making templates into first class objects. It would have been better to add something like 'inst-with' to extend inst.
If that change is a show stopper for you, then I would just fork anarki and eliminate the template changes, or fork Arc 3.1 and add the file upload change.
Also, can you provide some insight as to what you're doing? Are you just creating a HNish clone with file uploads for added content? As I mentioned in the other post, I wouldn't use that stuff for data storage anyway. So maybe consider making more dramatic changes and use a db?
I'm not aware of a save table issue. I just ran this and had no problems:
arc> (save-table (obj a 10 b 20) "tfile")
nil
arc> (load-tables "tfile")
(#hash((b . 20) (a . 10)))
edit: IMHO I would avoid using save-table/load-table as data storage mechanism. It may work for certain application designs[1], but otherwise you would be better off writing to a real database.
This link has been very helpful to me in the past and I'm glad it exists. But I do wish it contained only one sentence. The sentence that is the most important one.
I tried Anarki before but I recall at the time it wasn't backwards compatible with Arc. There was something about saving and reading tables that required specifying their datatype that differed from Arc. Has this changed?
I would like to use a version that also supports file uploads. Anarki is the only version I know of that supports them. Do other Arc implementations support file uploads?
I suggest starting with Anarki: https://github.com/arclanguage/anarki if you haven't already. Noting the readme instructions also point to racket rather than mzscheme.
Yes, I was trying arcueid becauze mzscheme wasn't working. The stack trace above is from arcueid, not mzscheme. I didn't consider using racket but I'm trying it now.
I'm using Arc 3.1. I don't know if it has the mutable-pair bugfix. I wish there were updated instructions somewhere explaining what's recommended or stable.
I'll try arc-nu too if racket crashes too. Thank you for these questions, they helped.
If these questions don't help, one last idea is to try Pauan's https://github.com/arclanguage/arc-nu, which seems to be a better-quality implementation of the arc core. I haven't played with it much, but reports of what's broken might get me to do so, knock it into shape.
Another option to consider is pointing us at your code. If nothing else, you'll get information about whether we're able to reproduce your problem on various combinations of platform+arc. As you might have noticed before, providing a concrete failing scenario often yields better answers. (And narrowing it down to just a little code is even better.)
For dido: How do you start arcueid? Should you load "libs.arc" to get all the libraries? (I get 'Unbound symbol: _color' otherwise)
Also, v0.1.3 crashes for me:
$ /usr/local/arcueid/bin/arcueid --include=`pwd`
Arcueid 0.1.3 REPL Copyright (c) 2013 Rafael R. Sevilla
This is free software; see the source code for copying conditions.
There is ABSOLUTELY NO WARRANTY; for details type (warranty)
arc> (load "libs.arc")
*** redefining arg
nil
arc> (load "mywebapp.arc")
*** redefining nbsp
*** redefining input
*** redefining submit
*** redefining menu
Segmentation fault (core dumped)
$ gdb /usr/local/arcueid/bin/arcueid GNU gdb (GDB) 7.5-ubuntu
Copyright (C) 2012 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "i686-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /usr/local/arcueid/bin/arcueid...done.
(gdb) run --include=/home/me/arc3.1
Starting program: /usr/local/arcueid/bin/arcueid --include=/home/me/arc3.1
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/i386-linux-gnu/libthread_db.so.1".
Arcueid 0.1.3 REPL Copyright (c) 2013 Rafael R. Sevilla
This is free software; see the source code for copying conditions.
There is ABSOLUTELY NO WARRANTY; for details type (warranty)
arc> (load "libs.arc")
*** redefining arg
nil
arc> (load "mywebapp.arc")
*** redefining nbsp
*** redefining input
*** redefining submit
*** redefining menu
Program received signal SIGSEGV, Segmentation fault.
0xb7fa9918 in arc_append (c=0x804c120 <cc>, thr=177156352) at cons.c:327
327 AFCALL(arc_mkaff(c, arc_apply, CNIL),
(gdb) bt
#0 0xb7fa9918 in arc_append (c=0x804c120 <cc>, thr=177156352) at cons.c:327
#1 0xb7f9de68 in __arc_resume_aff (c=c@entry=0x804c120 <cc>, thr=thr@entry=177156352)
at ccode.c:263
#2 0xb7fc9e76 in __arc_thr_trampoline (c=c@entry=0x804c120 <cc>, thr=thr@entry=177156352,
state=<optimized out>, state@entry=TR_RESUME) at vmengine.c:104
#3 0xb7fc62d0 in arc_thread_dispatch (c=0x804c120 <cc>) at thread.c:405
#4 0x08049526 in main (argc=1, argv=0xbffff704) at repl.c:590
Sorry, that toy example is too small for me. I don't understand why this macro redefinition approach would lead to that snag (although it does look like a plausible snag to end up in ^_^ ). Could you give some more context?
---
"Perhaps it's impossible to do if commas don't expand to unquote ?"
From what you're saying, it sounds like you're using some custom data structures, but that you just haven't given yourself all the primitives you need to manipulate them.
I've been playing with this for a few days, and I'm still stuck on how to modify this decl:
(def foo (a) `(list ,a))
so that:
arc> (foo 3)
(list 3)
instead returns (list ,3). How can you generate a literal unquote? Perhaps this is a bug in wart's core? Perhaps it's impossible to do if commas don't expand to unquote?
Most interesting. I wonder how the environment knows when to draw a circle. The visualization piece lives and dies by how much work it is to setup for more abstract code.
From my experience, the term "Dataflow programming" is an overarching concept for both Flow-Based Programming and Reactive Programming.
I use the term "Pure Dataflow Programming" in reference to the original idea put forth by Bert Sutherland's paper "The On-line Graphical Specification of Computer Procedures" and others. It is characterized by fine grain operations (small operations like add or subtract) and the assumption that dataflow concepts will be employed for all levels of an application.
Flow-Based Programming takes the Dataflow concepts but says that the nodes (aka components) should be programmed using our current, sequential, control-flow programming languages. The Dataflow graph is a layer above and it controls the execution of the nodes.
Reactive Programming is a newer term. I use it to mean Dataflow using the push model (nodes only execute when data is pushed to it). It is "reactive" to changing data.
There is a tower of babble in respect to Dataflow terminology because we haven't yet defined a common meaning for all the terms. These are my definitions for the terms but everyone seems to define things slightly different.
I will have a chapter in the book that explains all the terms and their common synonyms.
As Dataflow concepts are just now starting to come to the attention of the masses, we don't have any consensus on the best, or most common, Dataflow implementation architecture. So the book will cover all the tiny variations of Dataflow architectures and compare them to each other for their pros and cons.
If you're old enough to remember when OOP started to hit the front pages, you may remember the debate between prototype based OOP and class based OOP. For the most part, class based OOP is the most common model by far. Thus, books now only cover class based OOP. Unfortunately for me, Dataflow programming has not reached that maturity level yet so I try to cover all variations and let the reader decide what is best.
What's your personal background like? When I Google your name I mainly get a bunch of news articles about this Kickstarter. :-p (Edit: Oh, whoops. You have a bio on Kickstarter after all. http://www.kickstarter.com/profile/1712125778)
What would you say the difference is between "flow-based programming," "reactive programming," and "dataflow programming"? It sounds like you're making useful distinctions but that I just don't know what they are.
Skimming through the comments, I haven't fallen in love with the thread-first operator, but I'm unfamiliar with it. Perhaps I'd become more used to it in time.
I would sometimes do this:
(def recstring (test s (o start 0))
(let helper (afn (i)
(and (< i (len s))
(or (test i)
(self (+ i 1)))))
(helper start)))
In Arc, my immediate approach would be to define 'push as a macro, but also to give it a procedure version that's just a little more verbose. Then we can extend the procedure version and leave the macro version alone.
Here's some working Arc 3.1 code, which calls the macro "my-push", rather than overwriting Arc's own 'push:
That said, it's okay to drop the ((fn () ...)) in this case, since the code inside doesn't refer to caller_scope.
---
"I'm still not convinced I fully understand why eval and fn each add an indirection to caller_scope ."
(For the moment, I'm going to overlook eval here.)
That's just how you chose to build it, right? Isn't the whole point of caller_scope that it's specific to the current call?
I think the main issue you're encountering is that you always use the same name, "caller_scope", resulting in shadowing. Kernel uses an explicit parameter, as in ($vau () env ...), but Wart doesn't. This isn't necessarily a problem, because you can do something like this to work around the shadowing when necessary:
(fn (x)
(let my_scope caller_scope
(fn (y)
...)))
If you actually want to call a variable "caller_scope" even though it's not the current caller scope, you might have trouble with that, but you do have a couple of options.
I think this code will evaluate the ... as though it's just inside the (fn (x) ...), so that it can see the correct binding of caller_scope:
Unfortunately, the ... can't see the binding of y.
If you tweak the language a bit, you could make the implicit caller_scope parameter get shadowed by the explicit parameters. That is, if a function is of the form (fn (caller_scope) ...), you could let it ignore its implicit caller_scope binding altogether. (Currently Wart treats this just like any other duplicate argument name, and it throws an error.) In that case, you could use this technique:
Unfortunately, the ... can see the binding of my_scope. You might be able to get around this with a gensym.
---
"I'm still not convinced I fully understand why eval and fn each add an indirection to caller_scope ."
(Now to tackle eval.)
Are you sure 'eval adds a layer of indirection? I think the only indirection you're encountering is caused by 'fn. I just tried it out in Wart to make sure:
The first ((fn () ...)) layer establishes a binding for caller_scope, but it's an empty environment. The second ((fn () ...)) layer establishes another binding for caller_scope, so now caller_scope is bound to a first-class environment with a single variable in it named "caller_scope".
Within this second layer, we get a true value for (caller_scope = caller_scope). This is just a sanity check.
We false value for (caller_scope = (eval 'caller_scope caller_scope)), presumably because we're comparing the two different environments we've established.
Finally, it seems we can successfully use ((fn () (eval '<foo> caller_scope)))) in place of <foo>, because although it introduces a new environment, it evals in the old one.
Here's another way we can verify that eval doesn't introduce its own binding for caller_scope:
((fn () (eval 'caller_scope caller_scope)))
020lookup.cc:28 no binding for caller_scope
=> nil
((fn () (eval '2 caller_scope)))
=> 2
This all seems reasonable to me.
---
"But I needed it to expand to this:"
let $old push
mac (push x s)
`(if (isa stack ,s)
(push ,x (rep ,s))
(,$old ,x ,s))
I think you almost got it there. What you really needed was this:
mac (push x s) :case `(isa stack ,s)
`(push ,x (rep ,s))
-->
let $old push
mac (push x s)
`(if ,`(isa stack ,s)
,`(push ,x (rep ,s))
(,$old ,x ,s))
The difference is the addition of two groups of ,` heiroglyphics.
In between the , and the ` you have "room to operate on the names before starting on the backquote":
mac (foo n) :case (let a .. `(isa foo-type ,a))
with (a ..
b ..)
`(bar ,a ,b)
-->
let $old foo
mac (foo n)
`(if ,(let a .. `(isa foo-type ,n))
,(with (a ..
b ..)
`(bar ,a ,b))
(,$old ,n))
Since this approach would work for Arc-style (compile time) macros, I think it's what you were really looking for. Your "final expansion" branches on run time information before generating the code, so it's specific to fexprs.
---
"But even if there isn't, I'm starting to question if lisp is indeed the hundred-year programming model. I'm starting to feel at the end of my tether, at the limits of what macroexpansion can cleanly support."
False alarm! I'm pretty sure this was just a case of being rusty at one's own programming language. ^_-
I'm a little leery of using pointer-based semantics. Probably because of my C background :p
Yeah, it's an interesting problem. One that I should probably understand better... I mean, I "get" it: the RAM machine model is simple. But I've not programmed enough C (or similar) to understand how far the semantics would permeate day-to-day programs.
There's the part of me that's like "oh, just have primitives to reference & dereference addresses; easy". I seem to recall Lisps that use something like (ref x) and (deref x), and the explicitness pleases me, coming from "modern" languages where you have to remember odd rules about whether/where things are passed as pointers. But then I read C code and see all these pointers-to-pointers all over the place---in spots of code where I normally wouldn't think of pointers at all. Then again, that might be endemic to C, where you're probably just being destructive by default.
I've always wondered how ML works out in this respect (http://homepages.inf.ed.ac.uk/stg/NOTES/node83.html). Its system seems elegant on first glance, but I have no experience in it. I seem to keep finding myself regretting this lately...I should pick up a project to scratch my ML-learning itch.
Also, and I'm not sure, but I have a sneaking suspicion I might need to w/uniq those input args. I just didn't get that far into arcs' internals last night.
I agree, mixing `(,form ,x) and `(,x ,form) is really ugly and I do like
animals!dog!thaddeus!age
much better - I forgot arc could do that lol.
Also, if anyone were really caught up on the strings as keys hiccup, the idiomatic approach for arc would likely be this: http://arclanguage.org/item?id=13006. If one could only find a pleasant & available symbol.
Thanks for that idea! No I don't have a second use case that requires dispatching on the value of macro args. I'll keep an eye out and report back.
I'm a little leery of using pointer-based semantics. Probably because of my C background :p Your analysis was very thorough, and I like that push doesn't silently modify the values of other variables besides the one requested. I hadn't noticed that subtlety before. Yet another reason to avoid scar and co.