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

I like this idea, because it doesn't involves special meaning of braces or Algol-style function calls. I just prefer

  (2 + (3 * (sqrt 4)))
to

  {2 + {3 * sqrt(4)}}
but maybe this is just me. You could even add a fancy analysis function to do precedence which would allow things like

  (2 + 3 * (sqrt 4))
Maybe I am missing something that would create difficulties for this system, but I tried the modification suggested above and it actually worked, so I am inclined to think this could be a good way to implement infix math.

-----

3 points by cadaver 6674 days ago | link

I thought about this a little bit and I suppose the simple way would be to determine precedence based on the particular functions the symbols are bound to, rather than on the symbols themselves. But wouldn't you really want symbol precedence?

-----


>> Is cdar supposed to be missing?

> yes

Wasn't the point keeping the names car and cdr so you can compose them? (I remember reading such in one of pg's essays.) Then it seems to me to take full advantage of that you need to provide those names for use.

I don't think it is unreasonable to do the following, but it is currently not provided in Arc:

arc> (cdar '((1 2 3) (4 5 6))) Error: "reference to undefined identifier: _cdar"

Maybe this is just me missing CL's four levels of composition of car and cdr.

-----

8 points by pg 6674 days ago | link

I didn't mean Arc will never have cdar. But to avoid having a language designed according to arbitrary rules rather than the actual demands of the task, I've been trying to be disciplined about not adding operators till I need them.

-----

5 points by parenthesis 6674 days ago | link

I suppose you can cdr:car .

On the one hand, it does feel like all the c....r s should be there.

On the other hand, I think cadr is pretty much the only one I ever actually use; and it is there.

-----

2 points by drcode 6674 days ago | link

I noticed this contradiction, too... :) If we're not going to use c[ad]r composability, why not just use unique, easily distinguishable names for all of these that don't compose:

  car  --> hd
  cdr  --> tl
  caar --> inner
  cddr --> skip2
  cadr --> second
...or something like that. Unique names would reduce errors.

-----

2 points by eds 6676 days ago | link | parent | on: Meta Forum Questions

For some reason I only see the down arrow on some of the posts... again not sure exactly how the internal mechanism for that works.

Thanks. (Not that I intend to vote anyone down :)

Update: Looking through some of the other threads, it seems that I can't vote down on comments older than a certain age. (Offhand I would guess this was when I got the 20th point of karma.) So I guess it does kind of make sense.

-----

1 point by eds 6674 days ago | link

Actually, it seems that I just can't vote down on any comment older than 24 hours. Even it is related to when I got the karma, it is also limited by the age of the post as well. Not that it really matters, just thought I'd post what I see.

And again, if anyone could post what is actually going on here, I wouldn't have to make guesses.

-----

2 points by sacado 6674 days ago | link

Yes, it IS related to when you got enough karma.

-----

2 points by eds 6677 days ago | link | parent | on: "Axioms" that might need to be added

Maybe with list splicing so you don't have to insert the list parameters at the end?

  (let numbers '(4 6 3)
    (+ 3 @numbers 7))

  [foo 'a 'b @^ 'c]
http://arclanguage.org/item?id=1920

-----

1 point by bogomipz 6676 days ago | link

Yes, by all means. Here, I was talking about currying, though, so splicing was not a concern.

I'm not quite sure whether @ should be allowed to reuse the list when used at the end, but I believe it would be most correct not to. So (like mentioned several times before) the dot notation means cons, while @ means splice, which is not the same thing, even when used at the end of the surrounding list.

-----

3 points by eds 6677 days ago | link | parent | on: New version

Playing around with combining ":" and "."....

  arc> (= x [+ 10 _])
  #<procedure: x>
  arc> (prn:prn.x 5)
  #<procedure: x>
  15
  15
  arc> (prn:prn.x 5)
  #<procedure: x>
  15
  15
  arc> (prn (prn.x 5))
  #<procedure: x>
  15
  15
  arc> (prn ((prn x) 5))
  #<procedure: x>
  15
  15
Is this actually the way the first expression is being expanded? I can think of situations where I would want (foo:bar.arg) to be expanded to (foo (bar arg)) not (foo ((bar arg))). Just a thought.

-----

2 points by sjs 6677 days ago | link

I think it makes sense.

  arc> (def add (x) [+ x _])
  #<procedure: add>
  arc> (map [prn:add.40:idfn _] (range 1 5))
  41
  42
  43
  44
  45
  (41 42 43 44 45)

-----


Think about the traditional lisp printer and pretty printer. It's just that in this case pretty might potentially mean that certain parentheses could be omitted if indentation could still make the meaning clear.

So you might potentially have a printer that wouldn't attempt to remove parentheses, and a pretty printer that would do so to an extent.

As for the reader, if parentheses were optional but still allowed in normal s-expressions, then you could probably get away with using the same reader for normal and indented input.

-----

1 point by ryantmulligan 6678 days ago | link

sounds like a lot of work, but more importantly I feel that the reader and printer would lack internal consistency. That is, it would be harder for programmers to wrap their head around the reader/printer concept.

-----

2 points by eds 6679 days ago | link | parent | on: Arc Indentation Syntax

Ok, I did a little more hacking, and made a Scheme version of the function I coded in CL earlier. Still nothing near usable, but it is enough that in about half a dozen lines of code you can hack ac.scm to use it instead of Scheme's normal read function. And because the function leaves normal lists alone, you can use it to load the normal arc.arc definitions without any problems.

(Note: if you actually want to try this, in addition to just adding (require "read-indentation.scm") and changing various instances of (read) to (read-indentation), you probably want to add (flush-output) after the (display "arc>") in the toplevel definition, or the REPL you'll get will be extremely messed up.)

http://blackthorncentral.net/files/read-indentation.scm

-----

5 points by eds 6680 days ago | link | parent | on: Arc Indentation Syntax

After a 15 minute search of the comments, I see that there seem to have been a small group of very strong objectors to SRFI 49. (Ok, maybe a more complete search would have reveal more objections, but really, I couldn't find that many.)

Anyways, I don't particularly see that as a reason not to try the syntax at all.

In particular, I don't see how this syntax would be a Bad Thing. I mean, Python uses such a syntax, and so do other languages. And Python hasn't gone down the tubes because of its use of an indentation based syntax. So why can't a Lisp use such a syntax? The conversion between normal S-expressions and indented expressions (or I-expressions to use the SRFI term) is fairly straight forward, the code looks almost exactly the same minus the parentheses, and you can even interface with the traditional reader such that expressions of the typical (...) form read in normally (this is in fact what my code does). In short I don't see a significant difference between Python and Lisp that allows Python to use the indentation and not Lisp, except possibly that Python has to define an entire syntax to accomplish this and Lisp only requires a single function to be defined.

I'm not claiming that my code will amount to anything (I would be very surprised if it did), but I am saying we shouldn't dismiss the indentation based syntax out of hand.

-----

1 point by almkglor 6680 days ago | link

For traditional Lisp (cond ...) forms, it will actually look pretty good:

  cond
    (test)
        (exp)
    (test2)
        (exp2)
However, for Arc-style if's, you can't use that - you have to:

  if
   (test)
   (exp)
   (test2)
   (exp2)

-----

2 points by eds 6680 days ago | link

Yeah, if's look like a problem with my current system. Although I would make a couple of comments on what you have above. With the current conversion, you don't need the parentheses in the second version:

  if          --->    (if
    test      --->      (test)
    exp       --->      (exp)
    test2     --->      (test2)
    exp2      --->      (exp2))
Not that doing so makes it much better, because you still can't indent the expressions beyond the tests (and you can't indent the final default case either). On the other hand, if you kept the parentheses, because starting a line with a list turns off the conversion in my current system, you could do a more traditional style:

  if
    (test) (exp)
    (test2) (exp2)
Which would get converted to the same thing. But that isn't really satisfactory for longer if statements, with tests and expressions that take a full line each, and with enough cases that different indentation for test and expressions is needed to make the thing readable. So the syntax would probably need some significant revisions before it would be actually usable in code of any significant size.

-----

3 points by almkglor 6680 days ago | link

Another nitpick: how would you translate this to your syntax, then?

   (if x
        m
       y
        n)
BTW a bunch of people (mostly started by David Wheeler) have been discussion such syntaxes. See:

https://lists.sourceforge.net/lists/listinfo/readable-discus...

-----

1 point by eds 6679 days ago | link

Considering the expression above is trivially small it would be easiest just to leave it as is. (My program doesn't mess around inside lists, it only tries to interpret free symbols at the top level of input.)

But I think I know what you are really getting at, because when the single letter symbols above are more complex expressions, converting the above gets much more difficult. The fact is, in a system where indentation is significant, you can't make arbitrary decisions about indentation to make the code look the way you want. So either you have to line everything up equally so you can't distinguish between test and expression, or you need to come up with some fancy indenting rules that somehow know what an if expression is supposed to look like. I don't particularly like the former, and I'm to lazy to really work on the latter, so that leaves us with just having the badly formatted if expressions. (Unless someone else can think of something. Maybe that discussion does, but I don't entirely have time to look through their archives right now.)

But at the very least I am having fun messing with Arc internals, so not all is lost.

-----

3 points by almkglor 6679 days ago | link

Actually no - the problem is that you said:

  if          --->    (if
    test      --->      (test)
    exp       --->      (exp)
    test2     --->      (test2)
    exp2      --->      (exp2))
So, what if I need the variable test, not the function test? Suppose instead I have something like this:

  (if
    test
       (exp
          (exp2
             (very-long-exp3 5 6 7 8))
          (some-random-exp4))
    test2
       (exp5
          (exp6)
          (exp7)))
If a naked symbol all by itself becomes (symbol), how do I format the syntax if I need symbol, not (symbol)?

-----

2 points by eds 6679 days ago | link

Yeah, I don't know what to do about that one. I've been thinking about it for a while, I just didn't know that was what you were asking.

I can't see any way to make indentation show you need just a symbol and not a function call with no arguments. You could add symbols, but that works against the removal of the parentheses in the first place.

Its a bit of a hack but if you had a simple read macro for an identity function you could do it. (Quote doesn't quite work because it prevents evaluation.) But say you had a function identity like such:

  (def identity (x) x)
And you defined a CL style read macro (e.g. $) to expand to (identity x). Then in my current function, because the read macro would expand before checking the subexpression to see if it was a list or not, you could do the following:

  if
    $test
      exp
        exp2
          very-long-exp3 5 6 7 8
        some-random-exp4
    $test2
      exp5
        exp6
          exp7
Which basically exchanges all the parentheses in the traditional version for a identity macro. Of course, it isn't exactly the same because you are adding extra meaning (the call to identity) to the expression. But maybe you could make it a macro instead of a function, and do the expansion at compile time (although this is dangerous because if you expanded the macro too soon you would defeat the purpose of using it in the first place...):

  (mac identity (x) x)
On the other hand you could alway just use traditional s-expressions in the middle of significant-indent code. The goal is to make parentheses optional, not to remove them entirely. Sometimes it may just be more convenient to leave them in than take them out.

-----

1 point by eds 6679 days ago | link

I just thought of another solution which might fix this problem without needing any special syntax characters.

If you consider that the reason we know to add parentheses around structures in the first place is the indentation of forms below the current line, then it is ambiguous whether a form with no nested forms should be wrapped in parentheses or not. If the system then does not assume the innermost forms are function calls, then it solves the problem of interpreting literals as function calls. Thus you can now do this:

  if
    test
    exp
      exp2
        (very-long-exp3 5 6 7 8)
      (some-random-exp4)
    test2
    exp5
      (exp6)
      (exp7)
Which cleans up many parentheses (removing all parentheses was never our goal in the first place), and doesn't result in the extra parentheses that were a problem before.

I found that it was trivial to implement this in my previous code. You can find the updated version at: http://blackthorncentral.net/files/read-indentation.scm

-----

1 point by almkglor 6678 days ago | link

Note that the above syntax is already what is pretty much the basis for all i-exprs in the mailinglist I posted, which is the main reason I posted the mailinglist.

-----

2 points by soegaard 6680 days ago | link

Small group?

Here is a challege: Find one (just 1) example where srfi 49 is used.

-----

2 points by eds 6680 days ago | link | parent | on: Ruby-like in place list expansion

Would it not be possible to use the "." syntax that already exists? For example, if + were defined something like this:

  (def + args
    ...)
Then to call + on a list a which contains '(1 2 3):

  (+ . a)
I know this doesn't work in the current Arc, but maybe support for it could be added. (Or maybe not if there is some other reason you can't do that with lists... but I can't think of any such reason.) At any rate you shouldn't have to define new syntax for it to make it work, you just have to make the interpreter eval the form (fn . args) correctly. (In CL it works if you try "(eval `(+ . ,a))", which isn't exactly the same thing, but gets at what I am proposing.)

-----

4 points by vsingh 6680 days ago | link

Your solution is not sufficiently general.

For example, it should keep working if the 'a' in (+ . a) is replaced with its actual value. In that case, we get:

    (+ . '(1 2 3))
which is the same thing as saying

    (+ . (quote (1 2 3))
which is equivalent to

    (+ quote (1 2 3))
which obviously doesn't do the same thing as

    (apply + '(1 2 3))
which is what you wanted.

-----

1 point by bogomipz 6672 days ago | link

That means (+ . (1 2 3)) does what you want, doesn't it?

Granted, to do the equivalent of (+ @(foo)) you would have to do;

  (let temp (foo)
       (+ . temp))
Which is not very nice at all, so I'm not arguing against @. On the contrary.

Edit: I used to think that . and @ would only differ in the sense that cons and splice have different list building semantics, but now I believe that they should also differ in the timing of the operation;

  (+ . (foo))  -> (+ foo)
  (+ . '(foo)) -> (+ quote foo)
  (+ @(foo))   -> what we want, given that foo returns a list
  (+ @'(foo))  -> (+ 'foo)

-----

2 points by shiro 6680 days ago | link

That's a tempting idea; the problem is that you can only use a single variable after the dot. Because of the very definition of S-expression,

    (+ . (f x y))
is indistinguishable from

    (+ f x y)
However, just allowing single-variable case may be good to cover typical cases.

-----

3 points by absz 6680 days ago | link

It's close, but doesn't quite have the same semantics: with your syntax, the variable has to be at the end, but using the @ for splicing, one can write (+ 1 2 @lst 3 4).

-----

2 points by bogomipz 6680 days ago | link

Yes, which also means the @ cannot reuse the lst object in this case, and therefore shouldn't do so when it happens to be at the end either. The dot is a notation for CONS, while @ would require copying the list that is spliced in.

Both . and @ are very useful and would be great to have available in any context.

-----


Is (x . y . zs) a valid list? Shouldn't it be (x y . zs)? Not that it really changes anything above... I just wanted to point it out.

-----

2 points by sjs 6680 days ago | link

If you think of the . here as Haskell's cons (:) then it makes sense. All the same, (x y . zs) can mean the exact same thing, not to mention it is shorter and familiar.

-----

2 points by almkglor 6680 days ago | link

Weird....

  arc> '(x . y . z)
  (y x z)

-----

5 points by soegaard 6678 days ago | link

Arc uses the PLT Scheme reader. The PLT Scheme reader has a non-standard (as compared to RnRS) extension, namely the double-dot notation. The double-dot notation is used to write "infix expressions".

Consider:

  (x . < . y)  is turned into  (< x y)
  (integer? boolean? . -> . void?) is turned into (-> integer? boolean? void?)
This reader extension can be turned off, but setting the appropriate parameter.

-----

1 point by sjs 6678 days ago | link

That is strange, and probably a bug. You can use up to 2 dots and the last dot is handled first, consing x and (z . nil) then consing y and (x (z . nil)). '(w x . y . z) gives (y w x z).

I can almost see how this bug appeared. Searching for the first part of a dotted expression yields (w x), and then searching for the 2nd part yields z. For some reason the expression becomes '(y . (w x z)); that I cannot explain without looking at the code.

-----

More