Arc Forumnew | comments | leaders | submit | drcode's commentslogin

> sequential statement thinking will not work

Actually, the best arc code IMO uses a fifty-fifty mix of functional and sequential thinking....

> my "set x" functions were clobbering each other

As a beginner you probably want to use '= instead- That's the more general command. Most arc lispers will only use 'set in rare cases.

> (def ugh (string) ...

Avoid naming the variable 'string: It will probably be OK, but since arc has functions and variables in the same namespace (google "lisp-1") you're clobbering the 'string function.

Here's how I'd rewrite this code (as far as I understand it, which isn't very far, I'm afraid so this is a very very rough approximation :-)

  (def ugh (str) 
   (let x 5
    (forlen i str 
       (let v (trunc:/ 12 (+ i 1))
         (if (is #\A str.i)
	     (++ x v)
	     (-- x v)))
    x))
The short of it is, you wouldn't necessarily get rid of the set (the '++ and '-- are just variants of 'set)

If you really, really wanted to get rid of the "sets" you could write something as the following, which is in pure functional style (you might not want to do this, though... there's better languages for experimenting with a pure FP style, like Haskell)

(Again, very rough, untested code)

  (def ugh (str) 
   (apply +
    5
    (map (fn (c i)
             (let x (trunc:/ 12 n)
                 (if (is #\A c)
                     x
                     (- 0 x))))
         str
         (range 1 len.str))))
If writing in this "pure" style really interest you, I'd suggest switching from arc to Haskell first. After 6 months of Haskell, writing code without "sets" will become second nature. (At that point, you'll also realize what a pain in the ass Haskell programming is and will return to arc :-)

Oh, and the posting trick is to surround your code by empty lines and have it indented two spaces.

-----

1 point by skenney26 6037 days ago | link

Another twist is to use the 'on interator which binds its first argument to each successive element and implicitly binds 'index to the index of that element.

  arc> (on c "arc" (prn index ":" c))
  0:a
  1:r
  2:c
  nil

  (def ugh (str)
    (let x 5
      (on c str
        (let v (trunc (/ 12 (+ index 1)))
          (if (is c #\A)
              (++ x v)
              (-- x v))))
      x))

-----

1 point by drcode 6037 days ago | link

ah... I should be using 'on more often....

-----

16 points by drcode 6094 days ago | link | parent | on: A thought: Arc <=> JS

I have a simple arc->js translator just for this purpose. Basically, a "parenscript" for arc.

It's needs a lot more work though before it's worth posting publicly- Not sure if/when I'll get around to doing this.

(If I get six or more points on this post I suppose I'd consider getting it out sooner for others to play with :-)

-----

4 points by drcode 6094 days ago | link

Ok- I still have a bit of work to do on it, but I'll try to release it in a couple weeks or so.

-----

2 points by andreyf 6060 days ago | link

This is a "parenscript" for Allegro Lisp/AllergroServe. Def. worth looking at

http://kantz.com/jason/programs/jsgen/

-----

1 point by andreyf 6094 days ago | link

I'm pretty n00b to Arc, could you please send me a copy privately to see how these things evolve?

anfedorov@gmail.com

-----

1 point by drcode 6094 days ago | link

done.

-----

3 points by drcode 6095 days ago | link | parent | on: Dumb question

Two reasons I can think of:

1. Regular quoting is far simpler and has a much lower cognitive load (i.e. there are less things you have to be careful about when you use it)

2. On occasion, you need to quote data that contains commas or comma-ats without expanding anything. For instance, you may want to quote a piece of code to send to eval and that could contain a macro.

Your points do carry some weight, though- However, quotes and backquotes are heavily used in the ugliest of ugly macrology, so having both symbols available makes life significantly easier in those cases IMHO even if the simple quote seems somewhat redundant.

-----

1 point by cchooper 6095 days ago | link

If you don't want the commas to be expanded, you can always add another quasi-quote.

-----

2 points by drcode 6099 days ago | link | parent | on: Packaging libraries

arcfn.org is a good stopgap

http://arcfn.com/doc/fnindex.html

-----

1 point by almkglor 6099 days ago | link

True; high quality documentation, too.

It's not being updated, but then. neither is Arc ^^

-----

4 points by drcode 6103 days ago | link | parent | on: Interesting macro 'focus

good point.

You're right from the standpoint that I hadn't noticed the similarity and should have. Your solution is probably the best yet for the example I gave.

But it's different in that reduce only works on simple lists- My main motivation for this type of command is for working with arbitrary and complex data structures, not just lists.

-----

3 points by rkts 6102 days ago | link

  (def greduce (iter)
    (fn (f xs y)
      (iter (fn args (= y (apply f y args))) xs)
      y))

  arc> (greduce.map + '(1 2 3) 0)
  6
  arc> (greduce.maptable (fn (y k v) (+ y v)) (obj 'a 1 'b 2 'c 3) 0)
  6
  ; etc...

-----

5 points by rkts 6102 days ago | link

I guess I should clarify this a bit. In other languages (e.g. OCaml), it's conventional for each data structure to provide an iterator and a fold/reduce function. In Arc, the convention seems to be to provide iterators but not folds. The above code shows that it's sufficient only to have iterators, and a left fold can be automatically derived.

Alternatively, we could have data structures provide a left fold and automatically derive an iterator:

  (def giter (fold)
    (fn (f xs)
      (fold (fn (y . args) (apply f args) nil) xs nil)))
Thus, (giter:greduce f) == f, and (greduce:giter g) == g.

-----

2 points by drcode 6102 days ago | link

thanks- This is interesting information for me.

-----


NewLisp has some nice ideas- I have a hard time though seeing the "big picture" for its design decisions.

I feel like I can understand the primary design decisions for arc pretty well- They are:

   1. KISS (Keep It Simple, Stupid)
   2. Code brevity (note code.arc for pg's thinking on this)
   3. Don't make the code look like line noise
I would argue that if you take these to the extreme, what you're left with is arc.

-----

1 point by Ramir 6100 days ago | link

Your suggested "primary design decisions" seem to concern exclusively syntax & reserved names for built-in operators. This is a very specific and very superfluous aspect, for the latter two are the thin outer skin of any programming language.

From what I have read, Arc goes much deeper in its design principles. Those can be enveloped as the thorough "bottom-upness" of design: both read & write access to the language, right through to its primitive elements.

And this is the direct result of Mr. Graham's popular relation of Arc's design philosophy (http://paulgraham.com/design.html): a programming language ought to strive to accomodate those who themselves are qualified to design languages, translators and compilers, among other things.

This is at the foundation of Lisp, and Arc is a promising language because its designers seem to have well understood that foundation.

What is left to add, though, are modern counterparts of those 1960-s innovations that made Lisp superior not only in principle, but in reality also.

-----

1 point by drcode 6103 days ago | link | parent | on: Interesting macro 'focus

Yup, looks like 'w/res is very close to 'focus.

Your 'best alternative for my example is extremely clever, but doesn't work:

  > (= *list-of-numbers* (6 2 4 5))
  > (best (fn (a b) (and odd.a (> a b))) *list-of-numbers*)

  6
I knew something was wrong with it, but it took me like half an hour to realize the flaw :)

...it can of course be fixed with extra flagging (well, it'll still fail on only lists of even numbers by not returning nil) but then you'll lose the brevity advantage over my solution.

-----

1 point by rincewind 6103 days ago | link

sorry, I hadn't had access to an Arc then.

  (best (fn (a b) (and odd.a (or even.b (> a b)))) '(6 2 4 5))
as mexpr:

  best[[a;b]-> odd[a] and (even[b] or a > b); list[6;2;4;5]];

-----

1 point by drcode 6103 days ago | link

yes, still a pretty good solution.

-----

4 points by drcode 6103 days ago | link | parent | on: Interesting macro 'focus

Your definition has a typo, I think- What you probably meant is:

  (mac focus (var . body)
    (w/uniq (storage unbound)
      `(withs (,storage nil
               ,var (fn ((o arg ',unbound))
                      (if (is arg ',unbound)
                          ,storage
                          (= ,storage arg))))
         ,@body  
         ,storage)))

-----

1 point by drcode 6103 days ago | link | parent | on: Interesting macro 'focus

I thought about that, but then thought it would prevent you from returning 'nil... but your solution handles that case.

I agree your definition is better.

-----

2 points by drcode 6104 days ago | link | parent | on: Looking for advice

I second the "gem list" comment.

Something else that would be hard to develop, but possibly pretty innovative, is if an arc package system were tied to a git-like patching system:

This means that a package could "modify" instead of just "adding" to the code.

In most languages, this wouldn't be a feature that makes sense. In those languages, packages simply override code instead of mutating it. However, since a central tenet of arc is to have extreme minimalism, it would be interesting if packages could avoid adding unnecessary bulk to the base language by allowing mutation of existing code.

So, for instance, a package that improves a basic arc language feature could actually "clean out" the previous version of the code right out of the base language. (The packaging system would of course retain a copy of the old code, in case the package is ever removed and the previous code needs to be restored)

Or, a package could just be a patch on a core file (like ac.scm) that enhances the core in some way. This way, a package system could be used even for aggressive language experimentation.

Hope I explained that well enough.

-----

1 point by stefano 6104 days ago | link

Seems interesting, but I don't know if it could be implemented in a simple manner. I think it would create quite a lot of confusion especially in the following situation: package A requires package B, package C requires a "modified" B, and package D requires both A and C. The conflict doesn't seem solvable, even with namespaces: B and B modified would live in the same namespace, unless the latter modifies also the namespace.

-----

1 point by almkglor 6103 days ago | link

I suggested adding "interfaces" to packages. So A might require <B>v1, while C requires <B>v1-modified. At the very least, loading C would fail if the copy of B available on the user's machine is the original that does not provide <B>v1-modified.

OF course, it still requires that the modified B provide the semantics for the original B so that it provides <B>v1 seamlessly.

-----

1 point by eds 6104 days ago | link

Interesting idea, but I'm having a hard time visualizing how it would work. How do you patch source code after it is compiled and being used in a running image? I am aware of the existing (let old foo (def foo (...) (bar (old ...)))) pattern, but you seem to be implying something more that this... Or am I completely off on that aspect of it?

-----

More