Arc Forumnew | comments | leaders | submit | skenney26's commentslogin
3 points by skenney26 5203 days ago | link | parent | on: Tiny quiz app

I like your rewrite of 'question.

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.

-----

1 point by skenney26 5203 days ago | link | parent | on: Tiny quiz app

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.

-----

2 points by akkartik 5203 days ago | link

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.

-----

1 point by skenney26 5203 days ago | link

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.

-----

1 point by skenney26 5412 days ago | link | parent | on: Table defaults

I like your idea of having a default that can be overridden.

The code above is actually Scheme (which Arc is implemented in). Getting and setting table values in Arc is much less clunky.

-----

1 point by Adlai 5412 days ago | link

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.

-----


Here's an alternative version of a step macro:

  (mac step (v init end by . body)
    (w/uniq (gi ge gtest gupdate)
     `(withs (,v nil ,gi ,init ,ge ,end
              ,gtest   (if (< ,gi ,ge) <= >=)
              ,gupdate (if (< ,gi ,ge) + -))
        (loop (set ,v ,gi)
              (,gtest ,v ,ge)
              (set ,v (,gupdate ,v ,by))
          ,@body))))

-----

1 point by thaddeus 5435 days ago | link

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).

    (mac step (v init end by . body)
     (if (isnt by 0) 
       (w/uniq (gi ge gtest gupdate)
        `(withs (,v nil ,gi ,init ,ge ,end
                 ,gtest   (if (< ,gi ,ge) <= >=)
                 ,gupdate (if (< ,gi ,ge) + -))
           (loop (set ,v ,gi)
                 (,gtest ,v ,ge)
                 (set ,v (,gupdate ,v (abs ,by)))
             ,@body))) nil ))
now passes these two test cases:

    (step i 5 10 -2 (prn i))
    (step i 0 1 0 (prn i))
Thanks! T.

-----

1 point by skenney26 5509 days ago | link | parent | on: Source table

Logically defs for function definitions and macs for macros would make the most sense. How are you planning on filtering them?

-----

1 point by shader 5509 days ago | link

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).

-----

2 points by cchooper 5509 days ago | link

  (eval symbol)

-----

1 point by shader 5509 days ago | link

That works, I suppose

-----

1 point by cchooper 5508 days ago | link

I'm afraid it's the only thing that works.

But there's nothing wrong with it. You're doing non-performance sensitive metaprogramming, which is a perfect example of where eval should be used.

-----

1 point by shader 5508 days ago | link

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. ;)

-----

1 point by cchooper 5505 days ago | link

varif will be better if you can use it in what you're doing. It doesn't evaluate its argument, which might make it useless to you.

-----

1 point by shader 5505 days ago | link

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.

-----

1 point by cchooper 5504 days ago | link

But do you need to evaluate the argument to varif in your implementation? If so, then it's no good to you.

-----

2 points by skenney26 5513 days ago | link | parent | on: Fold

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.

-----

2 points by rntz 5513 days ago | link

Interesting. I get the same results, even when I modify the test slightly to run on lists of different lengths:

    (def testmap (ntests map) (time (for i 0 ntests (map [* _ 3] (range 0 ntests)))))
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.

-----

3 points by rkts 5513 days ago | link

The difference is the call to (no xs). Swap the then/else cases in map1 and it runs as fast as your version.

-----

1 point by skenney26 5513 days ago | link | parent | on: Fold

Correction: rev is also twice as fast, but using a left fold rather than a right fold:

  (def foldl (f v xs)
    (if xs
        (foldl f (f (car xs) v) (cdr xs))
        v))

  (def rev (xs)
    (foldl (xy (cons x y)) nil xs))

-----

3 points by rntz 5513 days ago | link

(xy (cons x y)) is just 'cons.

    (def rev (xs) (foldl cons nil xs))
Although you write your foldl differently than mine; for me, it would be:

    (def rev (xs) (foldl flip.cons nil xs))

-----

1 point by skenney26 5513 days ago | link | parent | on: Fold

I guess the aesthetics of using _1, _2, etc. has always bothered me a little.

-----

1 point by shader 5513 days ago | link

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.

Anyway, it's an idea.

-----

1 point by absz 5513 days ago | link

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.

-----

1 point by shader 5513 days ago | link

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.

-----

2 points by skenney26 5513 days ago | link | parent | on: Fold

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.

-----

3 points by simonb 5513 days ago | link

This doesn't change the fact that your definition of fold blows the stack for large inputs.

P.S. the "you need right-fold" bit was obviously a brain-fart on my part, sorry.

-----

8 points by skenney26 5559 days ago | link | parent | on: This would make my programs shorter.

Why not just 'hash? Using 'hash would also help to distinguish hash-tables from html-tables in html.arc

-----

4 points by cchooper 5558 days ago | link

This bugs me too. Perhaps the rationale is that a hash table is not the same thing as a hash (key).

-----

More