I agree that 'ret would be more useful in other areas than here. In arc.arc 'best, 'summing, 'sum, 'listtab, 'copy, 'inst, 'w/table, 'memtable, and 'evtil all use this idiom of creating a local variable with 'let and then returning it.
Thanks for the feedback. I'll take a look at how rand-choice and pull can improve shuffle and choices.
I use between alot with numbers and would like a similar utility for strings, but I understand its confusing that the arguments to between work exclusively with strings but inclusively with numbers.
param is just mapping over a paired list. Infinite recursion shouldn't be a problem.
There's a call to param inside param's body. Isn't it the same fn? Ah, it's just the tag macro's private language.
between with a string == substring between delimiters.
between without a string == pick a random number in a range.
Is that right? It's not just about exclusive/inclusive, that's pretty different semantics.
I meant that the return value of the string version doesn't include the delimiters (between "ab" "ef" "abcdef"), while when something like (between 3 7) is called, the return value could also be 3 or 7.
Maybe it would make more sense to modify rand so that it could return numbers in a range if given 2 arguments.
Yeah, I can tell it's Scheme because of #f used for false, instead of NIL.
If it's possible to pass an optional parameter to an Arc-style hash-table lookup (one where you use the table name as the function), than that would also allow overriding a default to NIL, because the 'or in that Scheme code would return NIL rather than evaluating the hash-table-get for the original default.
A much better alternate version too. The redundant code in my hacked version was obvious and ugly, but I struggled reducing it to a simpler form... Thanks!
I made a few slight adjustments though, as it failed 2 of my test cases (however unlikely they are to occur, infinite runs scare me).
currently fns takes an optional filter argument, and defaults to prefix. i.e., you give it a string, and it keeps all of the keys from the "sig" table that begin with that string. So it finds both macs and defs.
I've modified my version so that a) if you don't give any arg it returns the signatures all currently defined functions and macros, and b) it can take unquoted symbols as input instead of just strings. That makes use from repl easier.
I don't know how I would filter defs from macs. Maybe have def and mac store them in a different table? How do you get the object associated with a symbol? If I knew that, we could filter based on (type key).
I just found the macro varif on Anarki, which returns the value if bound. Would that be better, or worse? I should think it might be a little better, but I don't know.
True, this is running, I think, in the repl. So I don't think it matters that much. But having a good way to look up the value of a symbol is kind of important, I think. I want to do similar things that might be used in a "performance-sensitive" environment, not that arc is really performance sensitive in general. ;)
rntz wanted two separate functions to search macs and defs, so I suggested filtering the sig table based on whether each symbol was a mac or fn; that would only be possible if there was a way to turn the symbol into a value we could take the type of.
The tests weren't exhaustive, just simple comparison tests:
(time (repeat 1000 (map1 [* _ 3] '(1 2 3 4 5))))
Comparing the different implementations of map1, the one using the definition of fold (foldr) at the top of the page was the fastest, followed by Arc's version, followed by Anarki's version (using the definitions of flip, foldl and foldr in rntz's comment).
These informal tests were repeated on best and rev with the same results. I honestly don't know why it's faster.
No matter the number of tests, though, the difference is only a millisecond or so, which is negligible as the size of the input increases or if the mapped function does nontrivial work.
However, I've also tried the non-tail-recursive fold on very large lists, and it doesn't appear to blow the stack. mzscheme probably does something to prevent this from happening, like allocating "stack" frames on the heap (a standard technique for implementing call/cc without stack-copying, and if your GC is good it's not much of a penalty). Given this, it seems more defensible that arc.arc's 'map1 et al are non-tail-recursive. I think I may change lib/util's foldr to use the OP's implementation.
If you don't like _1, _2, etc. we could implement the system discussed here: http://arclanguage.org/item?id=8617. Basically, bind the unbound symbols inside the brackets in alphabetical order. It would work with _, _1, _2 as usual, but also x, y. Generally when people do short functions of a few variables they pick them in alphabetical order, so it makes sense. I'm just not sure how to go about implementing it. Presumably it would have to search the body for symbols which fail the bound predicate. sort them, and use them as the argument list. Unfortunately, it sounds like a macro with run-time knowledge. I don't know if macros have information on whether a symbol is bound or not; I would presume not.
You could look at make-br-fn on Anarki; it crawls through the [] functions finding free variables of the form it wants (_\d+ or __). It might be possible to modify it to pick everything out, if we want to. The downside, of course, is that if you typo, say, string as strnig, the [] function will think it's a brand-new variable. And the other downside is that lexically speaking, '_10 < '_2, though we could always special-case numbers.
Ok, I'll look at make-br-fn. And I hadn't thought about _10 < _2. However, when is someone going to write a 10 arg function with no names? Sounds suspicious to me. I agree that strnig would cause problems. However, unless you are very lucky, calling the arg "strnig" in function position will cause as much of an error as calling strnig in a normal function call. Of course, to see how useful it really is, I'd have to try it. I think that in most cases where all you want is three vars a, b, & c, or x, y, and z, it should work fine. And look better than _1 _2 _3, with less typing.
The fold defined above is a right fold. As for defining other general utilities, this version of fold can be used to define any function that uses a right fold. For example:
(def len (xs)
(fold (xy (+ y 1)) 0 xs))
(def sumlength (xs)
(fold (fn (n (x y)) (list (+ n x) (+ 1 y))) '(0 0) xs))
Graham Hutton has written an excellent paper on fold called
"A tutorial on the universality and expressiveness of fold"
which includes these and other definitions.