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

I've been reading http://subjectivelisp.org/wiki/Differences_with_Nu and noticed that your definition of let permits multiple variables. I'm curious if you considered the use case of destructured binding:

  (let (a b) (list 3 4)
    ..)

-----

2 points by Pauan 4908 days ago | link

Shameless plug: this is how Nulan handles it:

  # Single binding
  w/var foo = 5
    ...
  
  # Multiple bindings, like "withs" in Arc
  w/var foo = 5
        bar = 10
    ...
  
  # Look, ma, destructuring works
  w/var {foo bar} = {1 2}
    ...

-----

1 point by akkartik 4908 days ago | link

Nice. What is the s-exp for each?

I've considered replacing with and just keeping the serial version. But I like encouraging myself to not worry about ordering as much as possible.

-----

2 points by Pauan 4908 days ago | link

Only supports a single variable currently, though it would be cool to support multiple:

  w/each x = {1 2 3}
    prn x
Nulan's macro system is not only hygienic, but it plays very nicely with customizable syntax too, as you can see in the definition of "w/each":

  $mac w/each -> {('=) x y} body
    w/uniq i len
      w/complex y
        'w/var len = y.length
           for (var i = 0) (i ~= len) (++ i)
             w/var x = y[i]
               body
And a couple more examples:

  # Simulating a `for` loop using a `while` loop
  $mac for -> init test incr body
    '| init
     | while test
         | body
         | incr

  for (var i = 0) (i < 10) (++ i)
    prn i


  # Simulating a `do..while` loop using a `while` loop
  $mac do -> body {('while) test}
    'while %t
       | body
       | if ~ test
           &break;

  var i = 0
  do
    | prn i
    | ++ i
    while (i < 10)
P.S. Sorry for hijacking the thread, but I've been itching to talk about Nulan, since I've made so much progress on it (as shown by the many commits on Github).

-----


via http://news.ycombinator.com/item?id=4909666

Example app in Tranquil: http://github.com/fjolnir/xnomad#readme

-----


> "There may be a fundamental law that the more underpowered the language, the easier it is to read."

That's a lot stronger claim than your original :) Aren't python, ruby, and haskell all high-power but easy to read?

There's the confounding effect of learnability; lisp gets more readable over time. There's also the confounding effect of density or difficulty. This quote captures both:

"If you're used to reading novels and newspaper articles, your first experience of reading a math paper can be dismaying. It could take half an hour to read a single page. And yet, I am pretty sure that the notation is not the problem, even though it may feel like it is. The math paper is hard to read because the ideas are hard. If you expressed the same ideas in prose (as mathematicians had to do before they evolved succinct notations), they wouldn't be any easier to read, because the paper would grow to the size of a book." (http://www.paulgraham.com/power.html)

-----

2 points by nburns 4913 days ago | link

I seem to have overlooked this post until just now...

Incidentally, I've never written python, ruby, or haskell, except for a tiny amount of python.

Good quote. I've been reading a lot of computer science papers lately, and I tend to skip over the math formulas and focus on the text. This could be because I'm reading them for "fun" and not because I have to for a class, or something. But I have always found it hard to take in dense notation, and preferred a conceptual argument. Maybe it's just that I have a deficiency in that area. But I think prose has the potential to carry powerful insights that are out of the reach of formulas; I suspect the problem is that succinct, brilliant prose is just incredibly hard to write. It's probably easier to just list formulas than to get deep ideas into prose. The reverse is also true, of course. Some ideas can only be expressed properly with notation.

But that probably has nothing to do with programming language syntax per se.

-----

1 point by rocketnia 4912 days ago | link

"I've been reading a lot of computer science papers lately, and I tend to skip over the math formulas and focus on the text."

I do that too. :) Unfortunately, at some point it gets hard to understand the prose without going back to read some of the fine details of the system they're talking about. XD

-----

2 points by nburns 4912 days ago | link

I tend to jump around. The introduction is usually boilerplate for the particular area of research, so it can be skipped. (I wonder how many different papers have told the story of the memory hierarchy and how it's getting more and more important as data gets bigger.) Then I try to figure out if the paper has anything important to say, before working on the math. I figure that sometimes the big idea of the paper is in the math, and other times, the big idea is in the text, and the math is just obligatory. (You can't publish a paper on an algorithm without spelling out the precise bounds on time and space, even if the formula contains 15 terms. Not all 15 terms can be important to the performance, but it certainly is important to put them in the paper.) I guess it depends on the field, but in the data structures papers I like to look at, it usually doesn't take a lot of math notation to express the key innovation.

-----

1 point by akkartik 4913 days ago | link

"But that probably has nothing to do with programming language syntax per se."

Why do you say that? Syntax is notation. Check out this paper by the guy who invented APL, when they gave him his Turing award: http://awards.acm.org/images/awards/140/articles/9147499.pdf

-----

2 points by nburns 4912 days ago | link

I don't disagree with you. I was arguing for the value of well-written prose.

Donald Knuth thinks that programs should be more like prose (http://en.wikipedia.org/wiki/Literate_programming) -- not that I've ever tried, or fully understand, literate programming.

-----


I've started reading the book, but am having trouble connecting it up to s-expressions. Can you elaborate on examples of traditional lisp code that violate its principles?

-----

3 points by nburns 4904 days ago | link

Sorry, I didn't see this for a while.

I didn't really mean to say that the book was directly applicable to the problem at hand; I was thinking of throwing in a disclaimer, but I guess I didn't. I don't have the book handy, but as I recall, some of the principles were things like grouping similar things together, and making things that are different look as different as possible. The author goes on to describe how these things determine where your eyes land and then move over the page, which consequently determines how easy or hard it is to make sense of; remarkably, it was true, as you can see from the examples. The insight was striking... I'm not sure how much of my current thinking was in the book and how much is extrapolation; but I think it's possible to bring the mindset of a graphic designer to something like code. I like how in PHP, variable references always have dollar signs attached. If you bring the mindset of a computer scientist only, you might say, well, the dollar signs are obviously to simplify the tokenization; if you can solve this engineering problem, you should get rid of them. But I think it probably makes a difference in helping your brain's "tokenizer." The connection to the design book might be tenuous, but it seems to me that you could connect it to the idea of making different things look different, or one of the other principles in the book. A minimalist implementation of lisp has practically no inherent structure, which is both a strength and a weakness. Before I knew anything about how to write lisp programs, I knew that lisp had lots and lots of parentheses. I think that if you ask programmers what they know about lisp, probably 10% have used it, and 90% know that it has lots of parentheses. This is the thing that stands out when you look at it.

I think that book is a good book, just in general, and probably not a waste of time to read. But I admit that a leap of imagination is required to see applications to programming language design. Maybe multiple leaps.

-----

2 points by rocketnia 4903 days ago | link

"I like how in PHP, variable references always have dollar signs attached. If you bring the mindset of a computer scientist only, you might say, well, the dollar signs are obviously to simplify the tokenization; if you can solve this engineering problem, you should get rid of them. But I think it probably makes a difference in helping your brain's "tokenizer.""

PHP took sigils from Perl, where Larry Wall said "Things that are different should look different" and used different sigils for different types. However, sigils in PHP, Perl, and shell syntax all make string interpolation possible, which is more of a tokenization issue. So I think sigils probably exist in PHP for both reasons.

As a side note, Groovy uses $foo or ${foo} to mark string-interpolated expressions, but that $ isn't used in other circumstances. It uses the sigil only where the tokenization really demands it.

Personally, I consider "different things should look different" to be a good justification for lisp syntax. If macros are really going to give programmers the power to make the language syntax their own, then language-imposed irregularity is at cross purposes with that open-endedness. I think the parentheses help programmers realize that they should look only at the variable names to determine meaningful differences between things.

---

"The author goes on to describe how these things determine where your eyes land and then move over the page, which consequently determines how easy or hard it is to make sense of; remarkably, it was true, as you can see from the examples."

Does the author just describe and demonstrate these things qualitatively, or are there also references to quantitative studies?

This is Arc Forum, where the regulars already know how to read lisp syntax. We may try to look at our culture with fresh eyes, but it isn't easy. And as I hope you can see, I justify lisp syntax for qualitative reasons similar to the ones you use against it, without really disagreeing with you.

Hard numbers are the kind of thing that would clarify which of these arguments should win, so that's what I hope to find in a thread about "concrete, objective reasons." I'm not surprised or offended that this discussion hasn't focused on the numbers, but I am a bit disappointed.

The Wikipedia article on readability (http://en.wikipedia.org/wiki/Readability) does seem to be heavy with empirical justification. ^_^

From the article: "Bonnie Meyer and others tried to use organization as a measure of reading ease. While this did not result in a formula, they showed that people read faster and retain more when the text is organized in topics. She found that a visible plan for presenting content greatly helps readers in to assess a text. A hierarchical plan shows how the parts of the text are related. It also aids the reader in blending new information into existing knowledge structures."

There's one point potentially in favor of object-oriented programming, where some of the inheritance and data-and-behavior bundling may be formally unhelpful, but (I feel) it does establish an informally organized structure over the code. On the other hand, it's almost never exactly the organization I feel is ideal for conveying my own program. Grr, subjectivity again. x_x

-----

2 points by Pauan 4903 days ago | link

"If macros are really going to give programmers the power to make the language syntax their own, then language-imposed irregularity is at cross purposes with that open-endedness. I think the parentheses help programmers realize that they should look only at the variable names to determine meaningful differences between things."

That's the beauty of Nulan's syntax system: it is almost completely customizable, feels very "Lispish", and plays very well with macros. You can now have your short syntax and the benefits of "code is data is code".

Even wart's system works pretty damn well, despite being much less powerful, because it has very simple rules for how to handle things.

I think the key to making syntax play well with Lisp is to make sure the syntax has a certain amount of simplicity and consistency, and is customizable. Basically, the syntax needs to follow the list structure. Beyond that, you can make it as crazy as you want.

-----

1 point by nburns 4901 days ago | link

>> PHP took sigils from Perl, where Larry Wall said "Things that are different should look different"

I didn't know that. Perl seems to me like a monstrosity. But I'm sure there are worthwhile aspects to it.

>> language-imposed irregularity is at cross purposes with that open-endedness

I agree. There seems to be a trade-off between flexibility and readability.

>> Does the author just describe and demonstrate these things qualitatively, or are there also references to quantitative studies?

It's not that kind of a book.

>> I justify lisp syntax for qualitative reasons similar to the ones you use against it

I'm not trying to argue against Lisp. I've proposed that there may be a trade-off between flexibility and readability, and Lisp sits at one end of that spectrum.

>> Bonnie Meyer and others tried to use organization as a measure of reading ease. While this did not result in a formula, they showed that people read faster and retain more when the text is organized in topics.

The kind of readability I'm talking about is at a much smaller scale, like being able to recognize a function call or a loop.

>> There's one point potentially in favor of object-oriented programming, where some of the inheritance and data-and-behavior bundling may be formally unhelpful, but (I feel) it does establish an informally organized structure over the code. On the other hand, it's almost never exactly the organization I feel is ideal for conveying my own program. Grr, subjectivity again. x_x

I agree. I think one of the problems with OOP is that it tries to organize everything into hierarchies. Most things in the real world don't fit into neat hierarchies.

Think of the problem of finding things on the web. Before it morphed into something else, Yahoo was about organizing the web into a hierarchy. Search engines, in contrast, are not hierarchical. It's clear that the search engine approach has won out over the Yahoo approach.

-----

3 points by akkartik 4898 days ago | link

rocketnia: ..Larry Wall said "Things that are different should look different"..

In the beginning, Perl was a simple language. It generalized awk with user-defined functions[1], explicit file handles (STDIN, FILE) and array variables. With the idea that different things should look different, you got sigils to namespace arrays and scalars away from keywords and the standard library[2].

Over time, however, it got more line-noise. % for hashes. & and -> for references. Constants like $_ got added, positional arguments. When you consider all the primitives and capabilities in the language today, do array/scalar variables really deserve their sigils? It feels a little like hungarian notation now that the standard library includes so much more than just functions on strings and arrays.

It's all very well to say "different things should look different", but "different" isn't some absolute property. Programming languages are human things, and subject to human limitations. Our visual and frontal cortex gets swamped by too much "difference". So we need to pick carefully what to make salient. And, above all, not paint ourselves into a corner with our early decisions.

rocketnia: "I think the parentheses help programmers realize that they should look only at the variable names to determine meaningful differences between things."

nburns: "The kind of readability I'm talking about is at a much smaller scale, like being able to recognize a function call or a loop."

The advantage of lisp isn't necessarily that it forces you to do without syntax entirely. Perhaps it is that it allows syntax to be tuned by project/codebase, to make decisions in the small based on the characteristics of the whole.

For several months now I've been sporadically mulling this rambling paper: http://davewest.us/pdfs/ducks.pdf. I'm not sure what it's trying to say, but the lesson that sticks to my mind is that of the Tibetan Thangka, arranging a number of stories spatially for maximum memetic power. A program doesn't have to be just a list of functions, macros, symbols and calls. Or indeed a long list of user stories. I'm starting to believe that it matters how things are arranged in the small, because it can help grasp how things are arranged in the large, help the program to get into my head, ensure I understand how it is organized in the large, keep me from messing up the architecture with my changes, and thereby help preserve the program's coherence over longer periods of time.

[1] nawk -- the first version of awk with user-defined functions -- was released in 1988 (http://en.wikipedia.org/wiki/AWK). Larry Wall had already released Perl in 1987.

[2] The initial release still used $ for hashes, and didn't yet allow & for functions calls (http://groups.google.com/group/comp.sources.unix/tree/browse...).

-----

2 points by nburns 4895 days ago | link

Wow... thanks for the awk history lesson. I didn't learn awk until about 10 years ago, but now it's one of my favorite programming languages. It's a fine example of a domain specific language.

My experience with lisp is basically limited to scheme, which is a major bias, I'm sure. I get the feeling that common lisp is a bit friendlier, and makes things like user-defined macros a bit easier. The scheme documentation on the web is not all that user-friendly, and I'm forced to confess that I've never created a macro.

-----

3 points by akkartik 4920 days ago | link | parent | on: How do I create an about page?

That's a cool forum!

I assume you're looking at the toprow function? (http://github.com/nex3/arc/blob/f311b3879c/lib/news.arc#L618) If the url is at /about all you have to do is add:

  (link "about")
under the link to "submit".

To create /about, use newsop. Here's a simple example to append to news.arc:

  (newsop about ()
    (shortpage user nil "about" "About" nil
      (pr "hihihi")))
Does this work? Feel free to ask more questions if it didn't. If it did work, read on.

---

If it works, you might notice that the "about" link on the top nav of the about page isn't highlighted like say the "new" link is for the corresponding page. To fix this, add "about" to toplabels, and change the call in toprow to this:

  (toplink "about" "about" label)
Now the "about" in shortpage gets passed to label in toprow and toplink has enough information to decide to highlight it.

Did that make sense?

-----


I'd like that! Sadly, I think we don't have lisp syntax in the browser for the same reason we don't have lisp syntax in all programming languages: most people aren't converted to its benefits.

-----

2 points by kinleyd 4921 days ago | link

According to Rich Hickey, the average person goes for what they find to be "simple" as defined as easy or familiar. Whereas the power of simple requires you to go beyond the easy or familiar, and that's always tough if you aren't willing to put in some effort on the learning curve.

The benefits follow, just like in other areas of our life. I think one good analogy is the average person's attitude to gratification which usually of the instant variety. Whereas the ones who do well in life are prepared to delay that gratification, choosing investing over spending, etc. The difference in outcome shows up many years later, but show up it does.

-----

2 points by ChristophRe 4921 days ago | link

Thank you for that.

Do you know the paper "INTUITIVE EQUALS FAMILIAR"?

http://www.asktog.com/papers/raskinintuit.html

-----


"..a single, canonical way.. like K&R style for C."

I don't follow. Isn't K&R just one possible indentation style for C-like languages? Curly on the same line vs next line, etc.?

-----

1 point by nburns 4927 days ago | link

See above reply to Pauan.

There are other styles, but the differences aren't all that significant. I like K&R.

-----


Thanks for the recommendation; I ordered the book.

I'll plug my whitespace-sensitive toy lisp as well: http://github.com/akkartik/wart#readme

  $ git clone http://github.com/akkartik/wart
  $ cd wart
  $ ./wart   # ./wart test runs tons of unit tests
I'd love to have you try it out and tell us if it requires less retraining.

-----

2 points by nburns 4927 days ago | link

Thanks. Your language looks like one I'd like to try. Getting rid of the outermost set of parens is a good idea; the fewer parens that you have to balance, the better. I haven't tried doing any serious programming in a whitespace-sensitive language. I've always found C very readable -- I think C hit a syntactic sweet spot. A lot of people must agree, judging by how many languages have copied C's style.

PS. The one whitespace-sensitive language I use often is make, if it counts. I like make's syntax.

-----

1 point by akkartik 4928 days ago | link | parent | on: Revisiting + vs join

It took me a while to understand why this should be. cartesian calls mem which calls testify, and testify uses is.

  (def testify (x)
    (if (isa x 'fn) x [is _ x]))
I think it should use iso. Can y'all think of any reasons that's a bad idea?

If we make that change, I'm not too concerned about whether + is like join. A caller of either shouldn't typically care whether they create new conses or not.

-----

2 points by rocketnia 4927 days ago | link

"I think it should use iso ."

Of course! A quick Google search for [site:arclanguage.org testify iso] turns up a few places Arc Forumgoers have talked about this before:

http://arclanguage.org/item?id=9183 (aw)

http://arclanguage.org/item?id=13678 (me)

http://arclanguage.org/item?id=13267 (me and you)

These were just my first three search results. :)

---

"A caller of either shouldn't typically care whether they create new conses or not."

Does anyone mutate association lists? It might matter there.

-----

1 point by akkartik 4927 days ago | link

There'll totally be places where it matters whether something conses or not. But that should reflect in the (longer) name, IMO. cons-minimal-append, mayhap?

-----

2 points by akkartik 4927 days ago | link

OMG, why didn't I fix anarki? Doing so now.

-----

2 points by zck 4927 days ago | link

It seems ugly that calling '+ changes the elements inside its arguments. Even if 'testify were changed, I still think '+ shouldn't do that.

-----

2 points by Pauan 4927 days ago | link

Yeah, definitely. The reason for the bug is because the Arc compiler uses Racket's "append" to do the join, which means it first needs to convert the Arc list to a Racket list, do the append, then convert back to an Arc list.

So there's two ways to fix this:

1) Change Arc to be like Arc/Nu, so that it doesn't need to do the conversion. I don't expect this to be too hard.

2) Write + in Arc, and have it call "join" when the first argument is a list. Then there's no discrepency between the two.

I actually dislike how the overloaded + is written in Arc, so I think having it call join instead would be great.

-----

1 point by akkartik 4927 days ago | link

Yeah I don't disagree. I just found it more fundamental to ask why it should be so subtle to debug.

Also, if the language used immutable conses then every cons would indeed have to change, so there's some rationale for keeping it purely functional.

I do totally agree that the two should be consistent. That sucks a lot.

-----

3 points by zck 4926 days ago | link

If the language used immutable conses, it still shouldn't have to change every cons. The issue here arises not because the list you pass in has different conses than the list returned, but because the elements of the list you pass in have different conses than the elements of the list returned.

Let's say we call (+ '((1) (2))). I'll draw the list this way:

  ( , . , )                   
    |   `-------> ( , . nil)  
    |               |         
    |               |         
    |               |         
    v               v         
   (1 . nil)       (2 . nil)
To my brain, there are two "kinds" of conses in the list: those that make up the top-level list itself, and those that make up the elements.

  top-level  ( , . , )                   
    conses     |   `-------> ( , . nil)  
               |               |         
               |               |         
               |               |         
   element     v               v         
    conses    (1 . nil)       (2 . nil)

And here's what I think should happen in the call to +

  these conses  ( , . , )
  can change      |   `-------> ( , . nil)
                  |               |
                  |               |
                  |               |
  these conses    v               v
  shouldn't      (1 . nil)       (2 . nil)
Similarly, if you call

  (+ (list (obj 1 2)))
Would you expect the hash table to have its elements copied into a new hash table? No, the same hashtable should be shared between the calling list and the returned list, even if the list itself has different conses. And indeed, this is the case (thanks again, evanrmurphy, for tryarc):

  arc> (def check-cars-obj (join-fun)
              (let x (list (obj 1 2))
                   (is (car (join-fun x))
                       (car x))))
  #<procedure: check-cars-obj>
  arc> (check-cars-obj +)
  t

-----

1 point by akkartik 4926 days ago | link

But the result should be:

  ( 1 . , )                   
        `-------> ( 2 . nil)
So the first of your element conses has to change too.

But you are right that not all the conses need to change. I finally understood Pauan's diagnosis, that it was arc copying nil vs () terminated lists. I've been against that 'feature' for a long time. My private fork just stays with () terminated lists: http://github.com/akkartik/arc

-----

2 points by zck 4926 days ago | link

That's neither '+ nor 'join :

  arc> (+ '((1) (2)))
  ((1) (2))
  arc> (join '((1) (2)))
  ((1) (2))
That's flatten:

  arc> (flat '((1) (2)))
  (1 2)

-----

1 point by akkartik 4926 days ago | link

Sorry, I think we've both managed to confuse each other. + and join on a single arg is just the identity function, right? Aren't these the cases we care about?

  arc> (+ '(1 2) '(3 4))
  (1 2 3 4)
My argument was that in the presence of mutable conses all the conses would have to change. After your response I'm correcting that to "all the outer conses (except in the last arg)".

Does this seem right? I was reading your previous comment without one wrapping set of parens.

-----

2 points by zck 4926 days ago | link

Yes, the outer conses all have to change, except for the last one. But the inner conses don't, and they are changed right now. That, specifically, is my problem with '+ . If you call (+ '(((((((1))))))) '(((((((2)))))))) , you shouldn't have to change fifteen conses, just one or two.

-----

4 points by Pauan 4926 days ago | link

akkartik: "I finally understood Pauan's diagnosis, that it was arc copying nil vs () terminated lists. I've been against that 'feature' for a long time."

Yes, but Arc/Nu manages to implement that Arc feature without conversion, so I don't consider it a problem with the feature, but a problem with the implementation.

---

akkartik: "+ and join on a single arg is just the identity function, right?"

Yes, but Arc does the conversion even if you pass in a single argument. So another possible solution to the problem is to change Arc to return the first argument unchanged when passed in a single argument.

---

zck: "If you call (+ '(((((((1))))))) '(((((((2)))))))) , you shouldn't have to change fifteen conses, just one or two."

Yes, you shouldn't have to. Arc uses ar-nil-terminate and ac-niltree to do the Arc->Racket->Arc conversion. ar-nil-terminate does a shallow copy, but ac-niltree does a deep copy. Simply changing ac-niltree wouldn't work, because I'm pretty sure other stuff depends on the deep copy.

However, the Arc compiler could be changed so that + uses a shallow version of ac-niltree. That's an interesting idea: how much stuff in the Arc compiler is currently using the deep ac-niltree when it could instead use a shallow ac-niltree?

-----

3 points by rocketnia 4926 days ago | link

"Arc uses ar-nil-terminate and ac-niltree to do the Arc->Racket->Arc conversion. ar-nil-terminate does a shallow copy, but ac-niltree does a deep copy.

However, the Arc compiler could be changed so that + uses a shallow version of ac-niltree."

That's the essence of the bug, as I see it. This fix is much shallower than the other fixes discussed, so this fix would make the most sense in a minimally updated variant of pg's Arc.

Should Anarki go for shallow or deep improvement? I've advocated shallow in the past, but now I'm thinking Arc oughta follow through on its promise to "break all your code," which of course means the entire network of hacks, libraries, help resources, and alternate language implementations we've built up so far. It would be nice to see Anarki become a fork of Arc/Nu and undergo deep improvements, without losing the Arc flavor.

-----

1 point by akkartik 4925 days ago | link

I agree. I feel uneasy about the shallow change to +; I'm sure the same bug exists in some other functions since deep niltree is the default.

(Confusing that you're using deep/shallow with two meanings in the same comment :)

-----

4 points by rocketnia 4925 days ago | link

"I feel uneasy about the shallow change to +; I'm sure the same bug exists in some other functions since deep niltree is the default."

From what I can see, there are only three places in the pg-Arc code where 'ac-niltree traverses too far, and they're all in ac.scm. Two are the definitions of + and ar-+2, and one is a misleading comment:

  ; Arc primitives written in Scheme should look like:
  
  ; (xdef foo (lambda (lst)
  ;           (ac-niltree (scheme-foo (ar-nil-terminate lst)))))
  
  ; That is, Arc lists are NIL-terminated. When calling a Scheme
  ; function that treats an argument as a list, call ar-nil-terminate
  ; to change NIL to '(). When returning any data created by Scheme
  ; to Arc, call ac-niltree to turn all '() into NIL.
  ; (hash-table-get doesn't use its argument as a list, so it doesn't
  ; need ar-nil-terminate).
From another point of view, there are only a few places where 'ac-niltree probably needs to be recursive. Those are in the definitions of 'ac-call, 'ac-mac-call, and 'ac-macex, where they deal with quotation and macroexpansion, the two ways literal code is made available to Arc programs.

The other uses of 'ac-niltree are in 'ar-coerce (string to cons), 'dir, and 'timedate, where the lists are flat anyway.

I only looked for uses in pg-Arc, not any code that's been derived from it.

https://github.com/nex3/arc/blob/official/ac.scm

-----

2 points by rocketnia 4925 days ago | link

"Confusing that you're using deep/shallow with two meanings in the same comment :)"

Whoops! My comment was originally going to stand on its own, but I adapted it into a reply when Pauan got to what I wanted to say first. :) I didn't notice the word overlap.

-----

1 point by akkartik 4925 days ago | link

Arc/Nu manages to implement that Arc feature without conversion

Hmm, can you elaborate on how it manages this? Is it just printing nil, but otherwise leaving the actual cons cells ()-terminated? (That option has probably been discussed multiple times: http://arclanguage.org/item?id=3094. I'm sure I mentioned it too at some point.)

-----

2 points by Pauan 4925 days ago | link

"Hmm, can you elaborate on how it manages this? Is it just printing nil, but otherwise leaving the actual cons cells ()-terminated? (That option has probably been discussed multiple times: http://arclanguage.org/item?id=3094. I'm sure I mentioned it too at some point.)"

Yes. And then "nil" is a global variable that is bound to (). I also have to do a few other things like changing quote so that it changes the symbol "nil" to (), but overall it isn't that hard to have perfect Arc compatibility, even without doing the conversion.

-----

2 points by Pauan 4925 days ago | link

In case you're curious, in order to accomodate () as 'nil, Arc/Nu had to change the following Arc functions: coerce, type, disp, write, quote, sread

And the places in the Arc/Nu source that treat () as 'nil:

https://github.com/Pauan/ar/blob/c8dea3f2d3a4f343ec633c81437...

https://github.com/Pauan/ar/blob/c8dea3f2d3a4f343ec633c81437...

https://github.com/Pauan/ar/blob/c8dea3f2d3a4f343ec633c81437...

https://github.com/Pauan/ar/blob/c8dea3f2d3a4f343ec633c81437...

https://github.com/Pauan/ar/blob/c8dea3f2d3a4f343ec633c81437...

https://github.com/Pauan/ar/blob/c8dea3f2d3a4f343ec633c81437...

16 lines total. Probably less than it would have taken to do the 'nil -> () conversion. But Arc can't tell the difference, unless I've overlooked something.

-----

1 point by akkartik 4925 days ago | link

ar-nil-terminate does a shallow copy, but ac-niltree does a deep copy.

Insane. I'm bummed I haven't noticed this before :( Has it come up in the past?

---

I also just noticed: It is _utterly_ insane that niltree converts () to nil, while nil-terminate does the opposite.

-----

1 point by Pauan 4925 days ago | link

"I also just noticed: It is _utterly_ insane that niltree converts () to nil, while nil-terminate does the opposite."

It's called "tree" because it recurses on the car. In other words, it traverses sublists. As for why it's called "nil", well, I guess that's because you can't use () in the name without using || quotes. I'd call them "nil->null" and "null->nil". Or perhaps "arc->racket" and "racket->arc".

-----

1 point by akkartik 4925 days ago | link

I've renamed ar-nil-terminate: http://github.com/nex3/arc/commit/c7a27e0157

-----


I'm resubmitting http://arclanguage.org/item?id=16697 because we didn't do it justice the first time around. I could swear I read it, and yet apparently I didn't notice many things:

a) The difference between + and join, which triggered this post (http://arclanguage.org/item?id=17074)

b) The idea of overloading * analogously to +. And of making avg variadic. zck, do you want to update anarki? I'm happy to do it otherwise.

c) Quotable quote: "I thought of no simple way to do this but functionally, using recursion. The second place winner, who wrote in Python, approached this imperatively, using mutable state. We actually had to explain our solutions to each other, as the minified versions were not easy to gather the algorithm from. Programming styles can be restrictive."

All this was worthy of comment the first time it was submitted. Thanks, zck.

-----

2 points by Pauan 4928 days ago | link

I'd be interested in seeing the Python version.

-----

3 points by zck 4928 days ago | link

The python version is:

  import math,itertools as i
  def f(k,p):
  	while(len(p)>k):
  		m=()
  		for r in i.combinations(p,2):
  			d=math.sqrt(sum(map(lambda x,y:(x-y)**2,*r)))
  			if d<m:m=d;x,y=r
  		t=p.remove;t(x);t(y);p+=[map(lambda g,h:(g+h)/2,x,y)]
		print p

-----

1 point by akkartik 4928 days ago | link

It occurs to me that avg is intended to be analogous to sum. Perhaps we could have two variants, avg and mean. Which one should be variadic, thoughts?

-----

2 points by rocketnia 4927 days ago | link

Well, essentially we already have 'avg:list as the variadic version. In fact, it looks like we can shave off two characters:

  (map(fn e avg.e)r t)
  (map avg:list r t)
I don't remember ever using 'avg except maybe to average some time measurements at the REPL, and I think the idiom (avg:accum ...) comes in handy for that. But I generally don't use arithmetic operators in my programs, probably due to the subject matter I choose.

Edit: Here's another opportunity:

  (cdr(mem _ s))
  (cdr:mem _ s)

-----

1 point by akkartik 4927 days ago | link

After I wrote that comment it seemed to me that variadic is more fundamental, because you can always convert lists using apply. But you're right that it's not hard to bounce between the two.

-----

More