You may recall how I attempted to do something along these lines a long time ago (comment: http://www.arclanguage.org/item?id=11529). The part I got stuck on was using macros in the definitions (not expansions) of macros, or in the definitions of functions I intended to use at compile time; so, for example, if I wanted to define the macro "xloop" to implement the function "tuples" and use "tuples" to implement an "=" macro, then that would not work. (My comment gives a similar example with "my-if".)
At a glance, I'm not sure whether your approach offers any hope of getting around this difficulty. Does it?
Yes. (That's what I meant by "the helper functions can be defined with a plain 'define' instead having to use 'define-for-syntax'")
But it then doesn't work with modules for the same reason. So it's not a solution yet, it just pushes around what doesn't work from one place to another.
Hmm, we should think about whether we'd want to use Racket modules anyway. Racket macros are more expressive (albeit harder to write) than Arc macros because they operate on syntax objects. But Racket modules don't seem very expressive to me: they aren't first class objects and they aren't parameterizable.
I'm guessing that a module system in the spirit of Arc would correspond more to Racket namespaces. Maybe I ought to be able to say something like:
(module arc
(load "foo.arc")
(bar))
which creates a new namespace, populates it with values from the arc namespace, evaluates the expressions within that namespace, and returns the namespace. Or something like that.
For reference, here are the definitions of "mod-expt", "mapn", and "num->digs" (which I used), plus their immediate dependencies.
(def fast-expt-* (a n one *)
(xloop (a a n n tt one)
(if (is n 0)
tt
even.n
(next (* a a) (/ n 2) tt)
(next a dec.n (* a tt)))))
(def mod-expt (a n m)
(fast-expt-* a n 1 (fn (x y) (mod (* x y) m))))
(def partial (f x)
(fn args (apply f x args)))
;(mapn f a b c d) = (mapn (fn (x) (mapn [f x _] c d)) a b)
(def mapn (f a b . xs)
(if no.xs
(map f (range a b))
(mapn [apply mapn (partial f _)
xs]
a b)))
(= div $.quotient)
(def accumulate (comb f xs init next done)
((afn (xs total)
(if (done xs)
total
(self (next xs) (comb (f xs) total))))
xs init))
(def num->digs (n (o base 10) (o size nil))
(let u (accumulate cons [mod _ base] n nil [div _ base] [is _ 0])
(if no.size
u
(join (n-of (- size len.u) 0)
u))))
Also, to comment on my naming practices (the function I called "ass"): I have to give it a name, 'cause I intend to type it repeatedly into the REPL. However, I don't want to spend time coming up with a good descriptive name, especially since I changed my mind at least once about what the function was supposed to do while writing it. (Originally I was going to make it return the ratio [number of powers of 2 with a 0 mod 10^k] / [number of powers of 2 mod 10^k]. But then I decided to make it return the list of those two quantities, instead. Had I given it a descriptive name, I would then have had to change it.)
Therefore, the thing to do is to give it a name I can remember in the immediate future. Also it should be short, so I can type it easily. So swearwords are an obvious choice, and I use them frequently. Sometimes I also use nonsense syllables or one- or two-character abbreviations; incidentally, I favor "u" as a local variable because it's the left index finger's home key on the Dvorak keyboard (which I use).
By the time I'm actually ready to save the definition to a file for future use, usually I've settled on the final form of the function, and I give it a better name. So my source code is usually more sensical and less obscene.
> Association lists could be (x 1 y 2) instead of ((x 1) (y 2))
Nice, I never consciously realized that. (I suppose we've been seeing it all along in replacing (let ((a 1) (b 2))) with (with (a 1 b 2)), but I never thought about remaking alists that way.) I think the single drawback of actually doing that is that O(n) lookup is now O(2n). [Obviously, if lookup time is a bottleneck, you probably should replace the alists with something else, like... tables! or AVL trees.]
It's an old concept, known as plists[1]. Common Lisp has them, and uses the same syntax that I'm proposing.
By the way, one benefit of alists is that you can iterate over them easier:
(each '(k v) '((a 1) (b 2) (c 3))
...)
Compared to the following, with a plist:
(each '(k v) (pair '(a 1 b 2 c 3))
...)
Which, incidentally, uses `pair` to create an alist, then iterate over that... I was thinking about how to solve this, and figured a form of destructuring might help:
aw is correct, though I feel like answering your question anyway. Your function, indented nicely:
(define (List-coins Val Coin)
(cond ((= 0 Val) 1)
((< Val 0))
(else (+ (List-coins (- Val (car Coin)) Coin)
(if (null? Coin)
0
(List-coins Val (cdr Coin)))))))
This function will recurse until either Val is 0 or negative, or Coin is '()/null/the empty list. However, if Coin is the empty list, then your function will evaluate to
(+ (List-coins (- Val (car Coin)) Coin)
(if ...))
which contains a call to (car Coin), which throws the error that you observe. Instead, you should put the (null? Coin) check earlier, probably in the cond expression:
(define (List-coins Val Coin)
(cond ((= 0 Val) 1)
((< Val 0))
((null? Coin) 0)
(else (+ (List-coins (- Val (car Coin)) Coin)
(List-coins Val (cdr Coin))))))
This still won't work, because there's no else-clause in the ((< Val 0)) part of cond. In that case, Val is negative, and there's no way to meaningfully make change by adding more coins, so it should return 0. Adding this in:
(define (List-coins Val Coin)
(cond ((= 0 Val) 1)
((< Val 0) 0)
((null? Coin) 0)
(else (+ (List-coins (- Val (car Coin)) Coin)
(List-coins Val (cdr Coin))))))
I wonder how the number of comments is calculated. HN certainly permits more. Perhaps news.arc normalizes hotness by the number of comments.. Hmm. I'm not sure this is a good idea.
If you'd like another way to do it, Chrome's "find" function displays the number of occurrences on the page, (and highlights them in yellow, and indicates with yellow where they are in the scrollbar), which I find extremely nice. And it is useful here; it says 18 instances of "by pauan" (case-insensitive) and 9 "by rocketnia". This counts the original post, by Pauan, so it would be a total of 17+9=26 (perhaps you accidentally counted that too). Similar tactics yield 63 instances of "by pauan" (including OP) and 22 "by rocketnia" on the second thread, for a total of 84 (not including OP). This actually matches with what you said, because now there are 129 comments; probably you and/or Pauan made two comments in between this comment and my writing this. (If you were actually counting on your fingers, that's pretty good.)
In the absence of this find thing, I'd probably use some Unix tools.
$ pbpaste | egrep -c 'by (Pauan|rocketnia)'
85
The drawback of these methods is that if someone actually says the phrase "by rocketnia" in a post, then that'll screw this up. This could be remedied by counting instances of actual links to names in the page source:
<a href="user?id=waterhouse">waterhouse</a>
Actually, that works perfectly, because you can't put such things in comments (if you type <> characters, they show up as &#<whatever>;, and a comment can't make a link to something but have the text be different (except perhaps in a submission... pretty ridiculous to submit someone's user page, though). Only drawback is that your own username shows up in the upper right corner, too, which isn't a comment (and, again, it counts the OP too). Still, it works pretty well otherwise.
If we subtract my name because it's an extra that shows up just because I'm logged in as me, then the rest of the numbers add to 129, which is the number of comments on the page. So it doesn't include the OP. This is because, in the HTML of these pages, the top of the page and the original post are on the same line of HTML; and I am not yet strong enough with the Force to make sed a) perform more than one substitution in a line while b) printing only the substituted part. (I have .* on both sides of the above to make it consume the rest of the line; the 'p' command prints the whole resulting line.)
Incidentally, stuff like this would be made easier by something that parsed HTML (can you tell that I like making my computer do these things for me?), that was insensitive to how stuff was broken up into lines. I've considered writing an HTML parser in Arc, but these Unix tools are good enough most of the time, and I haven't really felt the need.[1] (Perhaps I could take a look at that multi-line editing stuff... it seems it'd suck to enter that into a terminal, on separate lines. Maybe the semicolons would work. Probably something better would be better, though.) Any thoughts or experiences? (I can derail this thread all the way back into Arc!)
Oh, nice, you have addressed exactly what I was asking for. Hmm, but question... Why not do this? I mean, you mention that it's not the only way, but this seems to work and doesn't require anything like gensymming.
I guess the advantage of your approach is that you can choose to only import the functions you want. If that's particularly important for some reason, then, sure, do it. But I suspect it might actually be useful to import the entire module, especially at the REPL when you're just starting out using it. Particularly if you have a "scheme apropos" function.
I added the "sort <" part just now, by the way. Can't believe I didn't think to do that originally (though I did at least add it to the "aps" thing somewhat earlier).
There was something or other that wasn't working when using $ directly because it was Racket-specific and it didn't work in Arc's mzscheme module. I forget now what it was though. (Clearly parse-xml is a bad example as it does work with a simple require).
Thanks. :) I was hoping for a response like this. And hey, look, Akkartik has more posts in there than I do.
I actually did use Chrome, but I both overthought and underthought things: Since I knew Pauan and I had a majority, I tried to search for every non-Pauan, non-rocketnia post. XD I ended up stepping over every occurrence of "point", which was even worse than searching for the majority.
Once I had typed out "point", what I really wanted was to continue with "s? by (?!Pauan|rocketnia)".
(for future reference, that is, without speculating on why or why not someone may have made decisions in the past, but if someone runs into a similar problem in the future)
If:
a) you're running a web application on top of Arc, and
b) you have some very long pages that are taking a long time to render, and
c) it's a page that you actually want to be able display to your users
...then there are less drastic alternatives to kicking the page off the front page:
- you can increase caching (at the cost of the displayed page being a bit more out of date)
- break the page up into parts and add "next" and "prev" links
Knowing the code was written with a news site in mind, you could also theorize (or speculate, which ever makes you happier) that the author (aka pg) would value both the quality and currency of the content over pouring coding efforts into handling of overly active, and by that time, older posts.
All speculation of course. I'm just suggesting that, often, there are simple reasons for the choices made behind these kinds of decisions.
All the ideas you list are great ideas. It's funny though, even I spent a bunch of time writing a blogging platform and I still have not bothered to put paging into the listings. I figure at my current rate of posts, it will take me a year before I'll need to worry about it. There are things we should do, in our ideal world, and then there's what we need to do relative to all other things. So, again, I suggest that maybe the reasons for these kinds decisions can often be much simpler than we think. There's not always some elusive statistical computation with all kinds attention and detail poured into them.
[edit1] ignore the below point... point format tricked me up reading on my ultra small screen :)
I don't fully understand what this point has to do with anything:
I like the work you did, but how does this fit into the discussion or your comment? It seems out of place.
[edit2] Also I used to like the fact that this forum allowed for editing within the first hour. I could correct my mistakes before, I figured, anyone had time to even read them, lol... but, that's not working anymore and trying to respond to changing posts kinda sucks.
I wish this forum had a "save as draft" feature! Maybe I'll just write it somewhere else first.
I don't fully understand what this point has to do with anything: - provide a runnable example
If you have a web application that is running too slowly and you want help, then you make it possible for other people to help you if you provide a runnable example that demonstrates it running too slowly.
What I was doing was getting the AVL tree to work (which, by the way, took a certain amount of thinking, debugging, and rewriting). Implementing them with hash tables, with convenient notation, was entirely appropriate for the task at hand. And now that I've got it in working form, it's easy to go and replace the hash table parts with structs or something. In fact, I think that was pretty clearly on my mind, because I described in footnote 2, in some detail, how one might implement the nodes using things other than hash tables. It was not my intention that the nodes should forever remain hash tables. I think you misunderstand me greatly.
And by the way, I did re-implement it in C, using structs, before I wrote the original post. Here's an excerpt.
Feels good, man. (The above code, by the way, fails to free() the obsolete nodes. That could be fixed if necessary.) Fortunately, I didn't really have to debug that code; I cribbed directly from my Arc code.
In my case, you may consider anything written by me to be released into the public domain. I don't accept the notion of intellectual property rights[1].
Now, I would consider it dishonest to post a project with large parts of code taken from someone else's work without giving credit, and I am inclined to respect others' feelings and wishes. So you probably don't have to worry about me doing things you don't want with your ideas. But there is no way that I'm going to pretend that downloading my source code means agreeing to a binding contract with me, for which I get to prosecute you in court if you break it. If someone insisted that I use a license, I'd probably go for the WTFPL: http://sam.zoy.org/wtfpl/
Can't say I agree with your thoughts so far. And I am not sure how we as a society would benefit from ditching IP notions.
I get the sense you believe that it's a huge waste of time a nothing more than a money pit for legal expenses. I believe if they went away then the openness that we are experiencing in this day and age would dry up.
When a house craftsman comes to my house and builds me a stairwell, I can't take his work and re-sell it. If I could, then he would quickly go out of business.
You speak of being "somewhat creative" in order to get compensation, but the reality is that the playing field becomes so uneven that the dived between the rich (in this case often the corrupt) and poor becomes greater. That's not a good thing.
> I am not sure how we as a society would benefit from ditching IP notions.
Indirectly, by having a more consistent legal system. As I said, I believe pretty strongly in property rights, and I believe IP is inconsistent with property rights. Debate about either of those things is probably way off topic for the Arc Forum, even more so than it would be for Hacker News.
As for the rest of your arguments, they're all of the form "there are unfortunate consequences". I can take each one of them and argue that it wouldn't be as bad as you think--sometimes because it'd be bad for some people for a while, but people would adapt and we'd all probably be better off at the end of it--as is usually the case with technological revolutions. I could explain myself in more detail and give examples, and in fact I began to do so, but, again, this is probably not the place for such a debate. Suffice to say that I have reasons for my opinions; I've done a lot of reading, thinking, and arguing on the subject (with myself, with the things I read, and with friends); and in an extended debate, you'd probably concede that at least my reasoning made sense even if you didn't agree with some of my premises.
Well, I've stated my opinion, and beyond that, the matter has little practical importance. As I said, I'm inclined to respect people's wishes, and if I copy and paste anyone's code here, it's little trouble for me to copy and paste the text of the copyright and license or whatever as well. (It would only be a problem if you were using the GPL or something, which I believe is supposed to require me to release my entire project under the GPL.) And it certainly shouldn't be a problem when I give code to you guys.
It's fair to say this is not arc language topic, so I will try to not extend it. It really is an interesting topic. For the record, I am not against your ideas, I just not able to marry the ideas up to the results.
I can't say I like the concept of encouraging openness through censorship (which is basically how IP works, right?), but I think you're spot on there. I don't know the reality, but the rich have better marketers to determine how best to profit off of an idea and how best to make that profiting seem polite to the original creator. There are already times someone makes a deal with Hollywood and doesn't like the result; I don't think that's distinguishable from someone who doesn't get to have a say in any deal in the first place.
It would be nice if there were another option like the anarchic politeness waterhouse describes, but I think IP is the natural next step from that, being a law system to help courts encourage/enforce politeness on behalf of people who don't have enough marketing dollars or military power to encourage it themselves.
I think that's because the above semantics correspond more directly to assembly language, which I imagine was done because "switch" was defined back when that was either important or just not seen to be bad. (Perhaps I'm just making that up, though.) Here's how a switch statement would look in x64 assembly:
switch:
;put desired thing in rax, let's say
case_1:
cmp rax, val_1
jne case_2 ;jump if not equal
<case 1 code>
case_2:
cmp rax, val_2
jne case_3
<case 2 code>
case_3:
cmp rax, val_2
jne done
<case 3 code>
done:
<whatever>
By default, the machine will just plow through the remaining cases. If you want it to break out after one case, you have to tell it to do so:
switch:
;put desired thing in rax, let's say
case_1:
cmp rax, val_1
jne case_2 ;jump if not equal
<case 1 code>
jmp done ;jump.
case_2:
cmp rax, val_2
jne case_3
<case 2 code>
jmp done
case_3:
cmp rax, val_2
jne done
<case 3 code>
done:
<whatever>
Assembly language is kind of awesome, by the way. And so is the Miller-Rabin primality test. Some disorganized code: http://pastebin.com/raw.php?i=wRyQ2NAx
Fine. That's great and all for C, but I dislike how Java copied C word-for-word, and then JavaScript copied Java. It would have been nice if they had said, "hm... using continue rather than break would make a lot more sense."
It's not a huge deal, and developers can simply avoid switch if they don't like it. My point was merely that "JavaScript's switch sucks, Arc's (case) is awesome."
I've sometimes experienced extremely long delays with DrRacket (I use DrRacket as an editor; I use the command-line "racket" to interact with Arc, and haven't observed these delays with racket). Perhaps Pauan is using DrRacket? And as for why that happens... I think it was a) trying to complete a garbage collection with b) a large part of its memory put into swap space. I'm puzzled by how it could take so long to un-swap that much memory (max 360-ish MB)... perhaps it did it in an impressively inefficient way (like, load page 1 containing a certain cons cell, then seek the disk for page 25359 containing its car, then seek back to page 2 for the cdr, and so on). Also, perhaps displaying the "recycling" animation contributes to the problem. Hmm, perhaps I'll figure that out at some point.
If you're not using DrRacket, then I'm not sure what might cause it, other than some unlikely things (e.g. memory of "racket" was swapped to disk and you were moving massive files around).
Meanwhile, if you really care about string-searching, or find it to be a pain point, you may want to implement the awesome Boyer-Moore algorithm: http://en.wikipedia.org/wiki/Boyer-Moore
No, I'm just using Arc on the command line. Garbage collection was my bet, and you're right that it could have been swap as well.
---
Yeah, might actually be a good idea to integrate that into the base posmatch, but as I said, posmatch isn't actually that slow compared to Python's find, so the bottleneck is probably elsewhere.