Arc Forumnew | comments | leaders | submit | raymyers's commentslogin
1 point by raymyers 6254 days ago | link | parent | on: Filtering comments based on points

So basically you're talking about something like what Slashdot offers, i.e. customizable filters based on the community ratings?

-----

1 point by lojic 6254 days ago | link

Yes

-----

4 points by raymyers 6257 days ago | link | parent | on: keep and rem at the same time ?

I don't think there is a library call for this. The way to go would probably be:

    (def keep-rem (test seq) (list keep.test.seq rem.test.seq))
However, if you really wanted to do it in one pass, you might do this:

    (def keep-rem (test seq)
      (let f (testify test)
        (if (alist seq)
            ((afn (s)
               (if (no s) (list nil nil)
                   (let (tokeep torem) (self (cdr s))
                        (if (f (car s))
                            (list (cons (car s) tokeep) torem)
                            (list tokeep (cons (car s) torem))))))
             seq)
            (coerce (keep-rem test (coerce seq 'cons)) 'string))))
Then we could kick it up a notch with some pattern matching.

    (require "lib/defpat.arc")
    (def keep-rem (test seq)
      (let f (testify test)
        (if (alist seq)
            ((p-m:afn
              (())       (list nil nil)
              ((x . xs)) (let (tokeep torem) (self xs)
                              (if (f x)
                                  (list (cons x tokeep) torem)
                                  (list tokeep (cons x torem)))))
             seq)
            (coerce (keep-rem test (coerce seq 'cons)) 'string))))
Bam!

-----

2 points by rkts 6257 days ago | link

This is a rare case where I think the tail-recursive solution is more readable:

  (def partition (f xs)
    (if (alist xs)
      (let f (testify f)
        ((afn (xs a b)
           (if (no xs)
             (list (rev a) (rev b))
             (f (car xs))
               (self (cdr xs) (cons (car xs) a) b)
               (self (cdr xs) a (cons (car xs) b))))
         xs nil nil))
      (map [coerce _ 'string] (partition f (coerce xs 'cons)))))
Also, how about generalizing accum to multiple lists?

  (mac accums (accfns . body)
    (let gaccs (map [uniq] accfns)
      `(withs ,(mappend (fn (gacc accfn)
                          (list gacc 'nil accfn `[push _ ,gacc]))
                        gaccs accfns)
         ,@body
         (list ,@(map [list 'rev _] gaccs)))))

  (def partition (f xs)
    (if (alist xs)
      (let f (testify f)
        (accums (a b) (each x xs ((if (f x) a b) x))))
      (map [coerce _ 'string] (partition f (coerce xs 'cons)))))

-----

3 points by almkglor 6257 days ago | link

True, although the final (rev a) (rev b) loses some of the speed benefit in the tail-recursion. If we didn't care about order (which happens quite often) we can drop the (rev ...) things. Otherwise, we can use a modulo-cons form, but this exceedingly complicated.

accums seems good... I suggest pushing it on nex-3's arc-wiki.

What I would like to see is a proper order-preserving accum. Here's a try at a "reasonably efficient" implementation:

  (mac accumf (accfn . body)
    " Collects or accumulates the values given to all calls to `accfn' within
      `body' and returns a list of those values.  The returned list
      is in the same order as calls to `accfn'.
      See also [[accum]] [[summing]] "
    (w/uniq (hd tl)
      `(let (,hd ,tl ,accfn) nil
            (= ,accfn
              (fn (s)
                (if ,hd
                    (do (= ,hd (cons s nil)) (= ,tl ,hd))
                    (do (= (cdr ,tl) (cons s nil)) (= ,tl (cdr ,tl))))))
            ,@body
            hd))))

-----

2 points by sacado 6257 days ago | link

Thanks for your answers ! I think that might be an interesting functionnality to add in the core functions. I used it a few times, in quite different contexts. Partitioning a list from a given criteria looks like a frequent action...

-----


This came up yesterday. http://arclanguage.org/item?id=3449

Doesn't work in Arc2, but works in Anarki. Also doesn't work with macros, as you say. Macros aren't as big a deal however, because they cannot be shadowed by let or def, only by other macros with the same name.

Personally I think this is a pretty good answer to the hygiene issue. Probably not necessary in every single macro you write, but good if you intend lots of other people's code to use it.

-----

2 points by eds 6258 days ago | link

Yeah, I remember I had to change that to make my pure arc version of infix-eval work :)

-----

3 points by raymyers 6259 days ago | link | parent | on: Arc2.tar

I would encourage you to go ahead and try using git. However, here's a current snapshot of Anarki you can play with.

http://cadrlife.com/arc/arc-wiki.tar.gz

-----

2 points by raymyers 6259 days ago | link | parent | on: Hygienic Macros

Well interestingly enough, li ls and lst don't appear in the non-Scheme source of Arc, except for lst in the borrowed mergesort.

What about xs and ys, do we get the hounds too?

-----

1 point by kennytilton 6259 days ago | link

Looks like my code when it's a three-liner and it really is a bit much to be coding (in my Algebra program):

  (loop for denominator in denominators...
You are right (guessing at the implicit): "list" is a terrible name for a variable unless someone really is writing a general purpose list manipulation function, but we do see "lst" quite a bit over on c.l.lisp.

btw, the real question is whether you see "list" as a variable name in the Scheme source.

-----

1 point by tel 6259 days ago | link

xs, ys, as, bs set off my Haskell alarm. They're pretty obvious and general, but something about pattern matching makes them unavoidable:

   interleve [] _ = []
   interleve _ [] = []
   interleve (x:xs) (y:ys) = x:y:(interleve xs ys)

-----

3 points by raymyers 6259 days ago | link | parent | on: Hygienic Macros

While we're on the subject, I know a number of people have been saying that Arc's unhygenic macros problems are a problem, because things like this break in a lisp-1:

    (mac break (a b) `(list ,a ,b))
    (let list nil (break 1 2))  =>  Error
However, you can simply unquote the function values in the macro.

    (mac dont-break (a b) `(,list ,a ,b))
    (let list nil (dont-break 1 2))  =>  (1 2)

-----

3 points by cadaver 6259 days ago | link

To make this work for functions, you need to add ((procedure? s) s) to 'ac. Otherwise with arc2.tar:

  arc> (mac dont-break (a b) `(,list ,a ,b))
  #3(tagged mac #<procedure>)
  arc> (let list nil (dont-break 1 2))
  Error: "Bad object in expression #<procedure: list>"
Macros still remain a problem:

  (mac list-macro parms `(,list ,@parms))
  (mac break (a b) `(,list-macro ,a ,b))
  (break 1 2) => Error

-----

2 points by raymyers 6259 days ago | link

I stand corrected, it worked in Anarki :)

And yeah, it obviously wouldn't work for macros, but macros don't get shadowed by let blocks in the first place.

    (mac list-macro args `(list ,@args))
    (mac dont-break (a b) `(list-macro ,a ,b))
    (let list-macro nil (dont-break 1 2))  =>  (1 2)

-----

1 point by cadaver 6259 days ago | link

Then it is I who shall stand corrected :)

-----

2 points by bogomipz 6259 days ago | link

A problem with unquoting the function value is that if you redefine the function, any code that uses the macro will hold on to the original function as a literal. This means the solution doesn't lend itself well to exploratory programming.

-----

2 points by raymyers 6259 days ago | link

Yes, it is true that preventing redefinition will in fact prevent redefinition. Bear that in mind when preventing redefinition :)

-----

1 point by bogomipz 6259 days ago | link

Well, one could create a module system so that the macro would always see the function the way it was seen in the module where the macro was defined. Then, when the function name is rebound where the macro is applied, it doesn't affect the macro, but if the function is recompiled in its original module, it does affect the code produced by the macro. I'm not saying it's straight forward, but I do believe it's possible.

-----

1 point by raymyers 6260 days ago | link | parent | on: arc-mode.el for emacs

I think Slime lets you erase the prompt too. I wonder if there is a good reason for that...

-----

1 point by cooldude127 6260 days ago | link

just tried it. emacs says "text is read-only". which is what it should do. i haven't the slightest idea how it pulls this off, though.

-----

1 point by nex3 6260 days ago | link

Turns out it's just a simple option: comint-prompt-read-only. I've set it in Anarki.

-----

1 point by cooldude127 6260 days ago | link

that was far too easy. i wonder if it is possible to make it pretty print.

-----

1 point by nex3 6260 days ago | link

I think it just outputs whatever Arc sends its way. So this would really involve getting Arc to pretty-print its output.

-----

2 points by cooldude127 6260 days ago | link

that might not even be that difficult, but my main problem is arc's pretty printing (in "pprint.arc") is rather flawed.

-----

13 points by raymyers 6260 days ago | link | parent | on: arc-mode.el for emacs

"extras/arc.el" on the git. We have Eric and Nathan to thank.

http://git.nex-3.com/arc-wiki.git?a=blob_plain;f=extras/arc....

-----

3 points by lojic 6260 days ago | link

I guess I found my motivation for finally installing and learning git :) Did Eric or Nathan submit a post or comment about this? I'd like to give those boys some points.

-----

4 points by nex3 6260 days ago | link

I didn't, and I don't think Eric did either.

-----

6 points by raymyers 6261 days ago | link | parent | on: Scala style match-case

And if you like that, wait'll you see my new macro, hcase. ;)

    (def union (< xs ys)
      (hcase `(,xs ,ys)
        xs [] = xs
        [] ys = ys
        (x:xt) (y:yt) / (< x y) = (cons x (union < xt ys))
                      / (< y x) = (cons y (union < xs yt))
                      / otherwise = (cons x (union < xt yt))))

-----

3 points by almkglor 6258 days ago | link

code or it didn't happen ^^. That said, I fully intend to transform the p-m macro to use a different guard syntax, to wit:

  (p-m:def union
    (_ xs ())  xs
    (_ () ys)  ys
    (< (x . xs) (y . ys))
    || (< x y) (cons x (union < xs (cons y ys)))
    || t       (cons y (union < (cons x xs) ys)))

-----

3 points by raymyers 6258 days ago | link

It happened, and so did this. http://paste.lisp.org/display/56496 :)

    (hdef union
      _ xs [] = xs
      _ [] ys = ys
      < xs@(x:xt) ys@(y:yt) / (< x y) = (cons x (union < xt ys))
                            / (< y x) = (cons y (union < xs yt))
                            / otherwise = (cons x (union < xt yt)))

-----

3 points by almkglor 6257 days ago | link

Here's a suggestion: add the following bracket-detector stuff (untested):

  (let bracket-sample '[a.highly-unlikely!symbol]
    (def is-bracket (a)
       (is (car a) (car bracket-sample)))
    (def bracket-list (a)
       ((afn (a sample)
         (if
           (iso sample '(a.highly-unlikely!symbol))
              a
           (acons a)
              (or
                (self (car a) (car sample))
                (self (cdr a) (cdr sample)))))
        a bracket-sample)))
I then suggest you transform this code:

  (if (is 'make-br-fn (car a))
      (map transform-brackets (cadr a))
to:

  (if (is-bracket a)
      (map transform-brackets (bracket-list a))
This retains compatibility with Arcn, and allows bracket.scm to insert something other than 'make-br-fn.

-----

2 points by raymyers 6257 days ago | link

Yep, that would be an improvement. An even better way to do this might be to use a tree-based parser combinator library with embeddable semantics.

    (withs (bracket-contents nil
            bracket-pattern 
              `[,(sem [= bracket-contents _]
                      (many anything))])
      (carry-out (parse bracket-pattern '([something (in _) brackets])))
      bracket-contents)

  =>  (something (in _) brackets)
Yes, that one is real too.

-----

2 points by almkglor 6257 days ago | link

^^ again... code please! Seems pretty nice. Just wondering, does this use the parse combinator library on arc-wiki or is this something else? Haven't studied the parsec lib very well yet. If different, would it be possible to merge it into the arc-wiki lib/parsec.arc?

-----

3 points by raymyers 6257 days ago | link

Here ya go, lib/treeparse.arc. Unlike the sloppy proof of concept hcase, this one might actually be useful.

This is different from parsecomb.arc in a number of ways, one being that it operates on lists and trees while parsecomb takes strings. Parsecomb also appears to be broken...

-----

2 points by almkglor 6257 days ago | link

Thanks! I'll be reading it through a bit.

Incidentally, pg would like to conflate strings as a list of characters, so possibly with a "correct" implementation of treeparse we can still parse strings as well.

Possibly the brokenness in parsecomb currently is from the merge with arc1 and/or arc2

Edit: Hmm. Possibly you think this can be encapsulated using one of the module systems? Most of the components are functions anyway, and the existing macros end up evaluating to functions, so it may be possible to transform them to higher-level functions instead.

-----

2 points by raymyers 6257 days ago | link

It would be nice to put it in a module, seeing as it binds allot of useful words. I like your module1plus, but without macro support it is hard to contain this library.

The macros seq, alt, cant-see, many, and many1 may appear to be expressible as functions, but they need to be macros to reference parsers not yet created.

    (= a (alt 'y (many b)))
    ;; `b' is not bound yet, but will be by the time `a' is used.
    (= b (alt 'x (many a)))
    (parse a '(x y))

-----

1 point by almkglor 6256 days ago | link

Oh, bummer. I guess I got too used to lazy evaluation in Haskell.

Macro support... dang. It's kind hard to scan through the code looking for macro definitions, and then you need to have them exportable, meaning you need the original list - and exportable macros will not be able to refer to the exporting environment (bummer).

-----

1 point by raymyers 6253 days ago | link

Macros in packages are a hard problem, no doubt. I still wonder if some degree of macrolet hackery might do the trick.

On a brighter note, I decided to make the lazy semantics of "lib/treeparse.arc" a special case, not the default. That way, there only needs to be one macro, delay-parser. Apart from making the code cleaner, this also makes a module more feasible.

-----

1 point by almkglor 6253 days ago | link

The problem is an expectation like the following:

  (module
    (module-vars foo)
    (interface settings
      foo-option)
    (def foo-option arg
      (if arg
        (= foo (car arg))
        foo))
   (mac macro-using-foo body
     `(do ,foo ,@body)))
Hmm. Maybe export the macros as functions. Hmm. This also means that everything within the module has to be macro-expanded, in case macroexpansion creates a reference to a module-based macro. Aargh.

-----

1 point by raymyers 6256 days ago | link

On second thought, that example goes into an infinite loop. Here's a more relevant one that does not.

    (= br (filt list:cadr:car `[,(many pattern)]))
    (= pattern (alt br anything))
Mutually recursive patterns are still a bit sketchy.

-----

3 points by raymyers 6257 days ago | link

Neat! The efficiency police might not dig it, but I would really like to see strings as lists. Haskell does this, and I think it's a big win.

-----

1 point by absz 6257 days ago | link

Is there any reason not to do

  (withs (ahus (uniq) bracket-sample `[,ahus])
    ...)

?

-----

1 point by cooldude127 6257 days ago | link

uniqs aren't really important since these are just functions. if they were macros, that would be another story.

-----

1 point by almkglor 6257 days ago | link

Hmm. You appear to be correct, this might be better.

-----

8 points by raymyers 6261 days ago | link | parent | on: premature optimizations in Arc

Minimizing the number axioms is good. Minimize the number of convenience macros is a different proposition. Most conditionals and closures don't need anaphora, so when I see the plain if or fn I know not there's nothing funny going on. The anaphoric versions tell me I need to look for the it/self references before I'll understand what I'm reading.

Other things we shouldn't do include eliminating let in favour of the more general with, and then eliminating with in favour of the more general withs.

Of course, (withs (a (foo) b (bar a) c (baz b)) ... ) is really just:

    ((fn (a) ((fn (b) ((fn (c) ... ) (baz b))) (bar a))) (foo))
So we could lose withs too...

-----

More