Arc Forumnew | comments | leaders | submit | shader's commentslogin
2 points by shader 5998 days ago | link | parent | on: Moved my hacks to hacks.catdancer.ws

Mind if I ask why you moved them away from github, and why you didn't move all of them?

-----

3 points by CatDancer 5998 days ago | link

I was using github's cool Github Page feature, where you can push a git repository to them, and they'll automatically create a web site out of it. The thing is, after you do the push, it goes into a queue, and some random time later depending on how busy github is the push will be processed to actually publish the changes. I found it was breaking my flow; the first thing I want to do when I publish something or write some instructions "go here and get this" is to try it and make sure that it's actually working. Nothing against github, it just wasn't a good fit for my particular work pattern.

I'm also slowly automating the hack documentation, so while naturally I do want to keep the source under version control it's just an extra step to have the generated HTML also in a git repository.

And I have aspirations of someday making this into a web app where anyone can publish their hacks, so it couldn't stay on github forever anyway.

I plan to still push the hacks to github, that way if my personal server goes down people won't be stuck waiting for me to fix it.

why you didn't move all of them

oh, I just don't have everything moved over yet.

-----

1 point by CatDancer 5998 days ago | link

And some were bug fixes for arc2 which have been fixed in arc3.

-----

2 points by shader 5999 days ago | link | parent | on: Multi character matching, and ssyntaxes

The idea of having symbol macros based on ssyntax was given to me by absz in http://www.arclanguage.org/item?id=9019

It doesn't seem too bad, hackwise, though I think it might have issues with layering new definitions on top of old ones if there isn't a way to remove them from the list.

What code would having that improved reader break?

-----

1 point by rntz 5998 days ago | link

Any code that relied on the ability to represent the symbol whose name is "foo.bar" (or any symbol containing a dot) as 'foo.bar rather than needing to wrap it in pipes as '|foo.bar|.

-----

1 point by shader 5999 days ago | link | parent | on: Multi character matching, and ssyntaxes

So, maybe an arc implementation of the reader is in order? Then we could have arc level implementation of reader macros too, instead of just ssyntaxes and symbol macros.

-----

1 point by conanite 5999 days ago | link

So far, we have lib/arc-read.pack and lib/parser.arc, both in anarki, as well as lib/parsecomb.arc. Not only do you have your reader, but you have a choice of them too!

arc-read seems to be designed for easy extensibility although I haven't tried it at all. (If I had looked carefully before embarking upon parser.arc, I might have saved myself a lot of trouble).

parser.arc doesn't support the full range of scheme numbers, nor does it support |foo| symbol syntax yet, apart from ||. I'm working on a new version that will hopefully be faster - welder depends on the tokeniser for syntax highlighting.

parsecomb.arc, if I understand correctly, isn't an arc parser but a library for building parsers.

In any case, having an implementation of 'read in arc makes a lot of sense, and it's in the todo at the top of arc.arc

-----

1 point by shader 5999 days ago | link | parent | on: Multi character matching, and ssyntaxes

That doesn't sound too hard to do. Assignment and position on strings are handled by string-set! and string-ref. If those were modified to accept a string as input instead of just a numerical index, then Adlai's code would work.

Maybe we should just make two scheme functions str-set! and str-ref and use those instead, as opposed to over-writing the original functions.

This sounds like a good spot for the redef macro ;)

Anyway, because position matching and assignment are handled separately, (= (str "world") "foo") could still work even without (str "world") returning a range.

-----

1 point by bogomipz 5999 days ago | link

Yes, there just seems to be a dilemma of whether (str "world") should return an index or a range. If Arc had multiple return values, it could return the start and end indices, and a client that only uses the start index would just ignore the second value :)

-----

2 points by Adlai 5998 days ago | link

The return value should correspond to what was being searched for.

In other words, searching for one character should return an index, while searching for a substring should return a range.

There are thus four operations which would ideally be possible through ("abc" x):

  arc> (= str "hello arc!")
  "hello arc!"
  arc> (str "arc")
  6..8     ; or some other way of representing a range
  arc> (str #\!)
  9
  arc> (str 5)
  #\space
  arc> (str 4..7)   ; same as previous comment
  "o ar"
A way to take advantage of multiple values, if they were available, could be something like this:

  arc> (str #\l)
  2
  3

-----

1 point by conanite 5998 days ago | link

Just curious - wouldn't it suffice to return the index of the beginning of the matched string when running a substring search?

  arc> (str "arc")
  6
, because you already know the length of "arc", so you don't really need a range result?

Otherwise, these are great ways to occupy the "semantic space" of string in fn position.

-----

1 point by shader 5998 days ago | link

I agree with you. I don't think that returning a range is necessary.

Even if call position and assignment weren't handled separately, it would still be possible to work off of the length of the argument and the index, without needing a range.

The question is whether or not pg agrees with us enough to add it to arc3 ;)

-----

1 point by conanite 5998 days ago | link

If there are 100 arc coders in the world, there are probably 100 versions of arc also. The question is whether you want it in your arc :)

-----

1 point by shader 5998 days ago | link

True. And I do. Unfortunately, I'm busy working on several other things at once right now. If you want to start working on it, be my guest. Hopefully I'll be able to share what I've been doing soon.

-----

1 point by Adlai 5998 days ago | link

I guess that (str "world") could just return an index, because (= (str "world") "arc") has access to the entire call, and can thus calculate

  (+ (str "world") (len "world"))
to figure out what the tail of the string should be after a substitution.

-----

1 point by shader 5998 days ago | link

Well, scheme supports multiple values, so it shouldn't be too hard to get them into arc, right?

-----

1 point by conanite 5998 days ago | link

arc supports multiple values via destructuring

  (let (a b c) (fn-returning-list-of-3-things)
    ...)
In the particular case of returning multiple indexes into a string though, you don't usually know in advance how many matches there will be, so destructuring isn't an option.

-----

1 point by Adlai 5998 days ago | link

Multiple return values from a form are allocated on the stack, not on the heap. I don't 100% understand what that means, though...

One practical consequence is that you don't have to deal with later multiple values if you don't want to, but when values are returned as a list, you have to deal with them.

-----


pg is letting us test it first, before making it an "official" release, so that he can catch most of the bugs before people start using it.

-----


pg's convention in the arc code is to just have one star after the name, instead of one on either side. Less typing, and it doesn't conflict with italics ;)

-----

1 point by shader 6001 days ago | link | parent | on: "ac-tunnel" proposal

Speaking of Anarki, what needs to be done to get it back up to date?

I haven't heard much about that. Maybe we should make a new thread about updating it?

You're comment about local variables made me think of something:

What if we used ac-tunnel, like CatDancer suggested, and then make mz defined as:

  (mac mz body
     (list 'ac-tunnel (cons 'quasiquote body)))
That way mz is defined in terms of the tunnel, and adds the feature of being able to unquote variables to pass the value through to scheme. $ had that feature, but called seval instead, so it lost the local environment. This way, we get the local environment, and the quasiquoting.

Thoughts?

-----

1 point by rntz 6001 days ago | link

Making the entire thing quasiquoted doesn't work. That would mean that the following:

    (let x 2 (mz (+ 2 ,x)))
Would compile down to this:

    ((lambda (x) `(+ 2 ,x)) 2)
Which obviously is not the intended functionality - it evaluates to the list (+ 2 2), not to the value 4. A quasiquote is, after all, a quote. So you'd need to add an 'eval outside it, and then you just have '$. Anyway, you already get the local environment with 'mz, because arc compiles local variables down to the same-named variables in mzscheme. That is to say, with 'mz as it currently stands, the following:

    (let x 2 (mz (+ 2 x)))
Compiles into:

    ((lambda (x) (+ 2 x)) 2)
So it just works! This does depend on the internals of the compiler, but then, that's the whole point of 'mz.

As for getting anarki back up to date, I discussed that a little in the arc3 release thread. Ultimately I think it's a wasted effort to try and port the entire thing. Instead I think the best idea is probably to port the best features from anarki (the help system, the ability to define how to call tagged objects, various utility functions and macros) separately to arc3, a la CatDancer's "Sharing arc hacks", and publish them as a sort of stripped-down new anarki. I've done some preliminary work here; in particular, I've ported the help subsystem to arc3. I have a repository at http://github.com/rntz/arc, though I haven't uploaded the help changes to it just yet and it's very badly organized. I think I'll probably make a more concerted effort once arc3.tar has been finalized.

-----

1 point by shader 6001 days ago | link

Right, I must have been thinking about globals, which need to be prefixed with "__". A bit uglier than a comma, but more effective ;)

Would it be possble to override 'unquote to temporarily mean

  [sym (string "__" _)]
? That way the syms would be transformed to the same way they are in mzscheme.

Ok, I guess I'll wait for upgrading Anarki until the final version of arc3.

-----

1 point by CatDancer 6000 days ago | link

Don't forget that when you write a macro

  (mac foo args ...)
You are given the full literal contents of what appears in (foo ...) in args. You can do anything you want to with it, including searching for (unquote x) forms and replacing them with something else. (The reader expands ,x into (unquote x), so that's what you'll see when you look at args).

-----

1 point by shader 6000 days ago | link

I've tried doing it several different ways, but so far nothing has worked.

I guess I'll just have to use __, or go with $, unless you can suggest a method to get that to work.

-----

1 point by CatDancer 6000 days ago | link

The first step is to start with an example:

  (= a 5)
  (= b 10)
  (mz (+ ,a (* ,b 2))
Now, what would you like this macro expression to expand into? Something like this?

  (with (x1 a x2 b)
    (ac-scheme (+ x1 (* x2 2))))
(yeah, this morning I'm trying out the name "ac-scheme" for "ac-tunnel" :-)

Now, let's say that expansion is what you want. So your next step is to write a program that takes

  (+ (unquote a) (* (unquote b) 2))
and turns it into

  (with (x1 a x2 b) (ac-scheme (+ x1 (* x2 2))))
this part has nothing to do with macros; you're just creating a list from another list.

  arc> (myprogram '(+ ,a (* ,b 2)))
  (with (x1 a x2 b) (ac-scheme (+ x1 (* x2 2))))
note that's a regular quote ' character there, not a backquote `. We're just feeding a regular old list to myprogram, and it's giving us a regular old list back.

OK! Got that program written? Now the macro is easy:

  (mac mz (x)
    (myprogram x))

-----

1 point by shader 6000 days ago | link

I'm aware of the process for making macros, however my attempts at writing the transformation itself have been rather unsuccessful.

What I originally tried was transforming

  (mz (+ 3 ,a))
into

  (mz (+ 3 __a))
But I couldn't get it to work. The problem is that I seem to need two levels of transformation and evaluation, but macros only give you one.

What is the reason that 'eval is so looked down upon? Isn't that pretty much what macros do themselves? How hard would it be to get an eval that could use the current local scope?

-----

3 points by rntz 6000 days ago | link

    (def transform (e)
      (if atom.e e
          (is car.e 'unquote) (ac-scheme.ac-global-name cadr.e)
          (map transform e)))

    (mac mz body
      `(ac-scheme (begin ,@(map transform body))))
For example:

    arc> (= e 'foo)
    foo
    arc> (mz (symbol->string ,e))
    "foo"

-----

1 point by shader 6000 days ago | link

Nice. Say, that brings up a thought I had earlier.

What if we made that pattern into a function called "maptree". I've needed something like that several times:

  (def maptree (f tree)
    (map (afn (node)
             (if atom.node
                 (f node)
                 (map self node)))
         tree))
It should apply f to each node of the tree, preserving the tree structure. Seems pretty useful to me, if you're going to be doing much transformation of arbitrary list structures.

-----

1 point by shader 5999 days ago | link

In retrospect, it's not much good for transforming the structure, but great for many other things.

For everything else, the other tree functions like trav, treewise, ontree, etc. might be more useful.

How would you make a more general purpose version of maptree that could encompass your transform function? It needs to be able to selectively modify some branches of the tree, and avoid calling map on them. Mine can't do that because it restricts you to atoms. Maybe if it took in two functions, one that operates on atoms, and one on lists, which can then optionally continue the mapping on a subnode. But then what has been gained? You're pretty much writing the whole pattern over again anyway.

Hmm. There seems to be a pattern here, but I can't see how to abstract it out, beyond the somewhat useful but restricted maptree posted above. Ideas?

-----

1 point by rntz 6000 days ago | link

'eval is not particularly looked down on, it's just rather inflexible. Given the way arc works, an 'eval that can use the current local scope is impossible - because arc compiles down into scheme, and an 'eval in arc compiles down to an 'eval in scheme, and an 'eval in scheme cannot use the current local scope. In order to get such an eval, you'd need to rewrite arc as an interpreter.

Edit: Unless mzscheme itself has some special 'eval with that functionality. I didn't think of that. I don't think it does, though.

-----

1 point by shader 6000 days ago | link

I guess I need to study how arc works a little more before I make any bold statements.

Couldn't you just apply the arc compiler/interpreter functions directly to a form? Didn't the parser.arc library do something like that?

-----

1 point by conanite 5999 days ago | link

parser.arc (at least, the parser lib I wrote; there are at least two others in anarki) uses coerce to get corresponding atoms from the token in string form. 'eval would probably have worked too. Otherwise, parser.arc just returns the forms it reads in, only transforming bracket syntax and string interpolations.

-----

1 point by CatDancer 6000 days ago | link

You actually only want one underline:

  arc> (= a 5)
  5
  arc> (ac-scheme _a)
  5
The ac-global-name function will prefix a symbol with an underline for you to create the global symbol name.

As for getting at the lexical scope, with eval or something else, that's up to the Scheme implementation. You'd need to go looking in the MzScheme documentation, or ask on the MzScheme user mailing list, to find out if there's some way to do that. Though why would you need that for this?

-----

1 point by shader 6000 days ago | link

This is what I got, using your mz patch:

  arc> (= a 5)
  5
  arc> (mz (+ 3 _a))
  Error: "reference to undefined identifier: _a"
  arc> (mz (+ 3 __a))
  8
So as far as I can tell, it's two, at least in Anarki on mzscheme 360.

-----

1 point by CatDancer 6000 days ago | link

Oh, I'm running arc3.

So, anyway, when you say you couldn't get "it" to work, what is the "it" that you're trying to do? I thought you were saying you didn't know how to transform "(mz (+ 3 ,a))" into "(mz (+ 3 __a))", but you say you know how to do that, so what is the it that's not working?

-----

1 point by CatDancer 6001 days ago | link

I've never used that feature, do you have an example handy of when auto-quasiquoting is useful?

-----

1 point by shader 6001 days ago | link

I'm working on that. First I have to get my snippet to work.

My goal is to get

  (= a 5)
  (mz (+ 3 ,a))
to transform into

  (ac-tunnel (+ 3 5))
so that you can use arc variables easily inside of a mzscheme call. That's what the original $ does.

-----

1 point by shader 6001 days ago | link | parent | on: How about + for tables?

Hmmm. Interesting idea, but I think it might be a little bit nuanced for the '+ symbol. I suppose if you make it work exactly the same way that it does for alists, then it would make sense, but otherwise you might want more general database functions, so that you can do different types of compositions.

What if you wanted to add the values of the fields? I.e.:

  arc> (+ (obj a 3 b 2) (obj a 4 b 1))
  #hash((a . 7) (b . 3))

-----

1 point by Adlai 6001 days ago | link

What you describe seems to be a mapping -- you're mapping the polymorphic '+ on each pair of values in the table.

Extending the idea of the polymorphic '+ on lists to include tables suggests what CatDancer proposed in the original post.

So I wrote up the following sketchy hacks of '+ for tables:

  ; arc3/tab-tests.arc

  (def table+ tbs
    (listtab (apply +
                    (map tablist
                         (rev tbs)))))
  ;; Conceptually transparent, but try to avoid
  ;; thinking about the wastefulness...

  (def table+-better tbs
    (w/table tb-new
      (each tb (rev tbs)
        (ontable k v tb
          (= (tb-new k) v)))))
  ;; Much better! Has a nice profile too :)

  ;; The rest is a "throw-away" test for the code
  ;; (require 'human-at-monitor-to-compare-tests)
  (with (ta (obj a 'ta
                 b 'ta)
         tb (obj b 'tb
                 c 'tb)
         tc (obj c 'tc
                 a 'tc))
    (map prn `("Consecutive lines should be identical:"
               ,(table+ ta tb tc)
               ,(table+-better ta tb tc)
               ,(table+ tb tc ta)
               ,(table+-better tb tc ta)
               ,(table+ tc ta tb)
               ,(table+-better tc ta tb))))

  ; Arc REPL
  Use (quit) to quit, (tl) to return here after an interrupt.
  arc> (load "tab-tests.arc")
  Consecutive lines should be identical:
  #hash((a . ta) (b . ta) (c . tb))
  #hash((a . ta) (b . ta) (c . tb))
  #hash((a . tc) (b . tb) (c . tb))
  #hash((a . tc) (b . tb) (c . tb))
  #hash((a . tc) (b . ta) (c . tc))
  #hash((a . tc) (b . ta) (c . tc))
  nil
So, the functions work. However, to get this as the behavior of '+ for tables would require adding a clause in ac.scm, to the following definition (from line 710):

  (xdef + (lambda args
             (cond ((null? args) 0)
                   ((all string? args) 
                    (apply string-append args))
                   ((all arc-list? args) 
                    (ac-niltree (apply append (map ar-nil-terminate args))))
                   (#t (apply + args)))))
My definition uses a bunch of higher-level functions defined quite a ways into arc.arc, but I need to use them in a low-level function in ac.scm. Should I implement the functions by hand into ac.scm, or is there a better solution?

EDIT: Someday I'll manage to format my code correctly the first time around...

-----

1 point by CatDancer 6001 days ago | link

is there a better solution?

try redefining + in Arc, for example

  (redef + args
    (apply (if (all [isa _ 'table] args)
                table+-better
                orig)
           args))
where redef is

  (mac redef (name args . body)
    `(let orig ,name
       (= ,name (fn ,args ,@body))))

-----

1 point by Adlai 6000 days ago | link

I guess putting the definition of + on hash tables into arc.arc makes sense. Either one of the algorithms is a more high-level procedure than the other behaviors of '+.

I like this 'redef macro. How come it's not in arc.arc already? I can't think of any reason to not have this be there, along with the definitions of other key macros like 'do, 'def, and 'mac.

Now, granted, this function actually contributes nothing to <insert large project here, including news.yc>. However, I think that this function strikes at the heart of the "hackable language" mentality, by making it much easier to quickly modify behavior on the fly. It also sends a message to somebody reading the source code: "One of the key principles in this language is that you can redefine behavior across the board with one macro call."

I think that for quick exploratory patches, it's a better solution than editing the original definition. If I want to modify this behavior, I just have one self-explanatory (redef + ...) form to edit, rather than having to sift through the original '+ definition. It is a clean solution, which adds hackability to the language.

-----

2 points by shader 6000 days ago | link

It's already included in Anarki, which until arc3 came out was the version used by the majority of the arc community. Probably still is.

-----

1 point by CatDancer 6000 days ago | link

I like this 'redef macro

You might also like my extend macro: http://catdancer.github.com/extend.html

You know, I had completely forgotten that I had used + on tables in my example of how to use extend...!

-----

1 point by Adlai 6000 days ago | link

'extend is great! However, I think it's more of a great library/patch, than something that should sit with the core functions. 'redef, on the other hand, is elegant, transparent ('extend is transparentially challenged...), and works well for quick hacks. 'extend seems to me to be more suited for setting in stone some behavior sketched out with 'redef (for example, the method-like behavior that you described in the original thread about 'extend http://arclanguage.org/item?id=8895)

The example you have of + on tables uses the algorithm that conses up a storm...

-----

1 point by CatDancer 6000 days ago | link

One thing I like about 'extend is that I can run it several times while developing an extension without my older, buggy versions remaining on the call chain. Try actually hacking with this version of 'redef, it turns out to be really quite a pain!

  arc> (redef + args
         (apply (if (sll [isa _ 'table] args)
                     table+-better
                     orig)
           args))
oops, typo, try again

  arc> (redef + args
         (apply (if (all [isa _ 'table] args)
                     table+-better
                     orig)
           args))
oops, this 'redef is now calling the previous 'redef, I'm stuck!

On the other hand I don't think the explicit separation in 'extend between the test of whether to apply the extension from the implementation of the extension has turned out to be all that useful, so maybe some combination of the two would be better.

-----

1 point by Adlai 5999 days ago | link

Rudimentary hack to fix that:

  (= old-def (table))

  (mac redef (name args . body)
    `(let orig ,name
       (= (old-def ',name) orig)
       (= ,name (fn ,args ,@body))))

  (mac undef (name)
    `(= ,name (old-def ',name)))
I tried storing a list as each value in the table, and popping or pushing to/from the list in redef and undef, so that you could step backwards more than just one definition at a time. However, that made the entire thing much more unstable, because it turns out that 'push and 'pop rely on a bunch of functionality which breaks quite easily if you're messing with the internals.

So, this stripped down version is my little 'redef/'undef hack-pack.

-----

2 points by shader 6001 days ago | link | parent | on: "ac-tunnel" proposal

Maybe it's just that I've been writing a lot of libraries, but I use 'mz a lot ;)

Besides, I can't imagine needing that combination of letters for anything else. Especially after having it refer to mzscheme for so long now, it would be hard to switch it.

-----

2 points by CatDancer 6001 days ago | link

I also really like "mz".

It doesn't matter to me what it gets named as. pg could add it to the Arc core as %%%internal-compile-to-mzscheme, and I could still use "mz" in the code I write using load-w/rename or some similar mechanism.

But hey, if everyone likes "mz", let's use that!

-----

1 point by Adlai 6001 days ago | link

I think that FOR NOW, 'mz is fine. Even though each person has their own patched-up Arc, it seems as though the vast majority are based on pg's Arc on mzscheme. If somebody is using an Arc built on some other VM (eg Rainbow on the JVM), then they will be putting quite different code within the body of an 'mz, so I don't think it's an issue that they'd also have to change the name of the symbol.

-----

2 points by shader 6001 days ago | link | parent | on: Running arc scripts directly? (Windows)

Here's what I would do:

Modify as.scm, or make a new scheme file that contains this code, slightly modified from Anarki's as.scm:

  ;load arc files
  (require mzscheme)
  (require "ac.scm")
  (require "brackets.scm")
  (use-bracket-readtable)

  ;compile arc.arc
  (if (and (file-exists? "arc.arc.scm") (< (file-or-directory-modify-seconds "arc.arc")
                                           (file-or-directory-modify-seconds "arc.arc.scm")))
      (load "arc.arc.scm")
      (begin
        (display "Compiling arc.arc...\n")
        (flush-output (current-output-port))
        (acompile "arc.arc")))
  (aload "libs.arc")
  
  ;either load a file or run the prompt
  (if (> (vector-length argv) 0)
      (begin
        (call-with-input-file
  	  (vector-ref argv 0)
  	aload1)
        (exit))
      (tl))
Then, if you're using powershell, you can create a function to save you some typing:

  function arc { mzscheme -fmv as.scm $args }
You may want to put this in you powershell profile:

  notepad $profile
Otherwise the function will only last as long as your powershell session.

When you're ready to use it, type either "arc" to just get the repl, or "arc file.arc" to execute the file. It's that easy!

-----

More