Arc Forumnew | comments | leaders | submit | vrk's commentslogin
6 points by vrk 6441 days ago | link | parent | on: Docstrings: a contrarian view

> Embedding docstrings in with the source also imply that functions and macros should be documented as they are written

This is how it should always be done. Encoding your ideas in any programming language is a lossy operation: it's difficult or impossible to determine from an arbitrary piece of source code what the intent and purpose of the programmer originally was. Good documentation gives the missing pieces.

I've found it incredibly helpful to write the documentation of functions before the function itself. Like you, I have a small head, and unless I know exactly what I should program beforehand, it's going to be difficult and messy to keep all details in mind. Describe the intent and purpose, give a canonical example of use (single line, or a couple of more if the function is variadic), rule out illegal input, and you're set.

Note that I'm not advocating long pieces of documentation. If you cannot describe a function well in a few lines, it's too big, and it's definitely not clear to you what it should be. If the documentation is in the same place as the source code, it is worlds easier to write the documentation, write the source code, then bounce between them while developing (since both usually require iteration).

I do not want to see idiotic documentation in Arc programs, but I doubt people who pick up Arc would do that anyway. I've seen many systems written in, e.g., Java, where documentation follows the same pattern as many Microsoft application help systems: "If you press the button called Print, you can print the document." or "Check here to enable grayscale printing" as a tooltip to a checkbox called "Enable grayscale printing".

-----

2 points by akkartik 6440 days ago | link

"Embedding docstrings in with the source also imply that functions and macros should be documented as they are written"

Not at all! It's been a mind-blowing experience to me to see documentation pop up in all of the arc codebase just because we had a wikipedia-like workflow.

People often don't want to talk about what they're doing when they are doing it. It's just human nature. This suggests another great time to document code: not when you write it, but when you read it and figure out what it does. A wiki allows this.

-----

1 point by partdavid 6440 days ago | link

Little discursive notes about why one thing works and something more obvious doesn't can be really helpful. Commentary about the code you didn't write can be helpful.

But in my experience on large projects that kind of documentation becomes:

   # do_my_foo() is a function accepts a float and
   # returns a float, performing necessary calculations.
   double do_my_foo(double inarg) {
   .
   .
   .
That is, they lie, they rot, and, since it's a "requirement" the programmer wasn't inclined to perform, they aren't informative, either.

-----

2 points by vrk 6442 days ago | link | parent | on: A proposal for a module system...

Some questions to consider before a module system is implemented:

1. Why?

I can see two different use cases for modules: a) controlled sharing and reuse; b) one more tool to encapsulate functionality inside the program. Which one is it, or is it both? Neither?

2. Should modules (module names) map directly to the file system hierarchy?

Why should they? Aren't they a different concept? Would it be reasonable to have more than one module per file, or more than one file per module? And what would happen when I wanted to move files?

Why shouldn't they? Aren't they ultimately saved in files?

3. Do we really need multiple namespaces?

Only a single namespace? Consider this: let the file or module where execution started from be the namespace. Let each imported/loaded module have an anonymous, uniq'd namespace from which symbols are imported. Repeat recursively, and you only get conflicts if you explicitly import two same symbols in a module.

-----

3 points by almkglor 6441 days ago | link

1. Reuse. Encapsulation is largely unnecessary, given with and withs (although I think we need withrec).

2. no:no:no:no:no:no:no

3. What you described is still multiple namespaces, even though we are just "working" on a single one - and besides, who says we'll be working on a single namespace when the Arc Server can serve several applications?

-----

1 point by vrk 6442 days ago | link | parent | on: Monadic-like macro

Definitely $_, although the initial value has to be defined here explicitly.

-----

2 points by applepie 6442 days ago | link

Now it behaves as Haskell's do-notation for the identity monad.

It could be adapted for other monads if it also took return and (>>=) as arguments.

  (mac w/ (monad x . rest)
    (w/uniq (gmonad)
      ((afn (x rest)
         (if (no rest)
           `(let ,gmonad ,monad ,x)
           (self `((car ,gmonad) (fn (_) ,(car rest)) ,x)
                 (cdr rest))))
       `((cdr ,gmonad) ,x))))

  (= list-ret list)
  (= list-bind mappend)

  (= list-monad (cons list-bind list-ret))

  (w/ list-monad 10
     (list (- _ 1) _ (+ _ 1))
     (list _ (* _ 2) (* _ 3)))

  ===>
  (9 18 27 10 20 30 11 22 33)

-----

2 points by vrk 6443 days ago | link | parent | on: Infix Math

Now that's an interesting idea. However, it would create some confusion if combined with the . operator:

  item!kids   ; Should really be item.'kids
  'kids.item  ; Huh? It's the same?
Granted, it would simplify some expressions, and you would get that "dot operator as in other programming languages" for free.

-----

1 point by eds 6443 days ago | link

I was under the impression cadaver was talking about infix math, because looking in the second position for the functional argument allows infixy syntax analysis.

You could combine it with the dot operator of course but I wouldn't really see a reason for it. (Why would you use 3.+.4 instead of (3 + 4)?)

And actually, the example you gave doesn't quite work (because of quote, you can't actually put a symbol in the functional position using the . operator).

  arc> (= item (table))
  #hash()
  arc> item!kids
  nil
  arc> 'kids.item
  kids.item

-----

2 points by vrk 6445 days ago | link | parent | on: Traversal

  (= src car)
  (= trg cadr)
  (= w car:cddr)

  (def make-edges l
    (let edges (join l (map [list trg._ src._ w._] l))
      (let from [keep (fn (e) (is src.e _)) edges]
          (rfn fetch (a)
              (if (no a) nil
                  (atom a) (from a)
                  (join (from car.a) (fetch cdr.a)))))))

  ; Dijkstra's algorithm.
  (def shortest-paths (edges s) 
    (with (T (table)
           S (table)
           num [case _ nil +inf.0 _])
      (= T.s 0)
      (= S.s t)
      (trav edges.s
         [map [= (T:trg _) (min (num:T:trg _) (+ (num:T:src _) w._))] _]
         [map [= (S:trg _) t] _]
         [let next (keep no:S:trg (edges (map trg _)))
                 (let m (apply min (map num:T:trg next))
                   (self (keep [<= (num:T:trg _) m] next)))])
      T))

  (= edges (make-edges 
                '(a b 2) '(a c 3)
                '(b c 2) '(b d 1) '(b e 3) '(b f 2)
                '(c e 1)
                '(d e 2) '(d f 1)
                '(e f 2)))

  (prn (shortest-paths edges 'a))
It looks a bit unwieldy, and one could argue this is perverse use of the trav macro, but there you have it.

-----

3 points by vrk 6445 days ago | link | parent | on: Problems with min

Thank you. Just shows how little I have really programmed in Lisp...

-----

2 points by vrk 6446 days ago | link | parent | on: Binary Search Trees in Arc

If by that you mean counting the nodes, you need to parse the source first. You can either do it by hand (if you know the grammar) or tweak the compiler/interpreter, if it doesn't have any statistics option.

-----


Is the prefix notation the biggest reason Lisp is not used more? No, I don't think so. Prefix, infix, or postfix is all a matter of what you are used to. It's possible to define the max operator as infix instead of prefix:

  (max 1 2) ; --> 2
  1 max 2   ; --> 2
It's associative (it's easy to prove). And after that you can do the regular stuff:

  1 max 3 max 2 max 5 ; --> 5 
Does this look natural? Usually max is more of a function, or in mathematics one usually writes

  max{ <some set> }
or with set comprehension

  max{ x : <some condition for x> } .
I find infix max easier in pen-and-paper calculations.

Coming back to Lisp and Arc, is familiarity the only reason you want infix math operators? The biggest benefit you get from prefix compared to infix is its regularity and uniformity. Control structures, function calls, and (now in Arc) array and hash table access are all identical. This means you can freely add not only new functions, but new control structures, without hacking the parser and the compiler.

One reason why this happens is that you don't have precedence levels. Precedence is always explicit (bar Arc's new intrasymbol operators, which are infix), and this is why Lisp mathematical functions, such as + and *, accept multiple arguments. The distinction between (+ 1 (+ 2 3)) and (+ (+ 1 2) 3) is useless and even harmful. It's best to write it (+ 1 2 3) or 1 + 2 + 3, because the operation is associative.

Aside from losing this, you also lose the concept that your whole program is a list. This stands at the heart of Lisp macros. How would you write macros for opaque infix blocks?

-----

5 points by almkglor 6446 days ago | link

> Aside from losing this, you also lose the concept that your whole program is a list. This stands at the heart of Lisp macros. How would you write macros for opaque infix blocks?

The solution which dwheeler on the readable-discuss list supports is to simply have the reader translate infix to postfix. Syntax like {1 + 2 + 3} becomes readily translated into (+ 1 2 3). What's more, dwheeler suggests that precedence should not be supported at all: {1 + 2 * 3} is a badly formed expression that the reader will reject, you must use {1 + {2 * 3}}.

-----

1 point by vrk 6446 days ago | link

That's an interesting idea, but on the other hand, if you don't have precedence defined for the common cases, how are infix expressions better than prefix? Does it save typing and cognitive load?

  {1 + {2 * 3}}
  (+ 1 (* 2 3))
Maybe it's a bit clearer, as it's more familiar. Could this be extended to arbitrary two-parameter functions?

  (def foo (x y) ...)
  {x foo y}  ; --> (foo x y)
Why do I ask? Because then we would have a way to write

  ; "Object-oriented" method call
  {object -> method}

  ; Different kinds of assignments, common in C/C++/Java/etc.
  ; (Perhaps of little worth in Arc.)
  {x += 1}
  {x -= 1}
  {x |= bits}

  ; A "binding" operator, or Pascal-like assignment.
  {x := 1}

  ; An arbitrary relation.
  {a R b}

  ; Perl 6 pipe operator [1] look-alike.
  {{data ==> [...]} ==> processed}
[1] http://www.perl.com/pub/a/2003/04/09/synopsis.html?page=2

-----

3 points by almkglor 6446 days ago | link

> Maybe it's a bit clearer, as it's more familiar. Could this be extended to arbitrary two-parameter functions?

This is, in fact, the reason why dwheeler decided to eschew precedence - I kept pestering him that in the future I might want to create a 'convoke operator or some other arbitrarily-named relation. Basically any {_ sym _ [sym _]...} pattern gets converted to (sym _ _ ...)

The problem with supporting precedence is that you have to define it before someone starts mixing up the order of the symbols. And dwheeler wanted to do it at read time, so you had to have fixed precedence at read time. If someone randomly typed {x sym1 y sym2 z}, the reader wouldn't be able to know if it's (sym1 x (sym2 y z)) or (sym2 (sym1 x y) z). Initially we were thinking of supporting only +-*/ precedence and disallow mixing of other operators, but this started to get slippery: where do you draw the line where some operators are allowed to have precedence and others are not?

-----

2 points by jc 6439 days ago | link

This suggestion may be a bit un-Arc, but I'd prefer a "with-infix" macro implementing a well-defined sub-language than I would some kind of integration into the reader. An optional precedence list arg might be a good idea.

The problem there is, of course, that the s-exprs generated by the macro are essentially a black box, but in my thinking, if infix is being used minimally and purely for convenience's sake, it isn't necessary to make those s-exprs accessible to other macros (right?...).

-----

2 points by vrk 6447 days ago | link | parent | on: Cut and Index - Arc and Ruby Side By Side

For reference, here's how you can do it in Perl 5:

The ith item of s:

  $s[i]
The ith item of s from the end:

  $s[-i]
The first x items of s:

  @s[0 .. x-1]
The last x items of s:

  @s[-x .. -1]
The items from position i to the end:

  @s[i .. $#s]
The items from position i to position j (exclusive):

  @s[i .. j-1]
i items beginning at position j:

  @s[j .. j+i]
The items from position i to the end minus the last j items:

  @s[i .. $#s-j]
  # Alternative:
  (@s[i .. $#s])[0 .. j-1]
i items beginning at the jth position from the end:

  @s[-j .. -j-i]
  # Alternative:
  (@s[-j .. -1])[0 .. i-1]
Legend:

  $s[i]  # A scalar at index i
  @s[<something complex>]  # An array slice (i.e. multiple values)
  $#s  # The last index of the array s
  a .. b  # In list context, a list of numbers or letters from a to b, inclusive (can be used outside array indexing)

-----

2 points by vrk 6447 days ago | link | parent | on: Using Arc at work

I'm not sure if I should applaud or shudder... what was the name of your company again?

-----

2 points by sacado 6447 days ago | link

Actually this is not critical code, so the relative immaturity of Arc is not really an issue. It's just a frontend for people scared by rsync or scp and it probably won't be used more than once a month anyway.

Spending too much time on it : that would have been the bad option. And using Perl or Python or PHP would have taken me much longer.

-----

2 points by sbraford 6443 days ago | link

Ahhh this brings back memories.

I did something similar when rails was first hitting the scene.

My boss/PM would've crapped his pants if he knew I was building toy RoR apps for the marketing dept. (it was a Windows shop) =)

-----

More