Arc Forumnew | comments | leaders | submitlogin
let redundant to with?
2 points by Johnny_65701 5828 days ago | 33 comments
Apologies in advance if this turns out to be a dumb question because it saeems to obvious not to have been thought of, but do you really need let and with? Isn't let just the degenerate case of with? It reminds me a little of the . and -> dereferencing operators in C; if the compiler knows enough to complain, it should know enough to just fix it for me.


2 points by absz 5828 days ago | link

let is a convenience for binding one variable; it allows you to leave out the parentheses of with. Do you need them both? No. But they're nice. (After all, you don't need either; both are equivalent to function calls.)

-----

1 point by skenney26 5828 days ago | link

let is just a convenience that allows you to type fewer parens:

  (let x 1
    (pr x))

  (with (x 1)
    (pr x))
I agree with you that it seems a little awkward to have so many macros just for binding local variables (let, with, withs).

-----

2 points by absz 5828 days ago | link

withs is actually fundamentally different in that the binding order is different; something defined later can refer to something defined earlier.

-----

1 point by bOR_ 5827 days ago | link

If there a way in which arc would understand

  (with x 1
     (pr x))
as well as

  (with (x 1 y 2)
     (pr x))
... initially, it would seem that you can distinguish the two by whether there's a ( following the with, but you might get into trouble:

  (let (x y) mylist
     (pr x y)
where let is followed by a (. mmm. I'm a still quite unfamiliar with arc or lisp. Can anyone give an example in which interchanging the "let" for a "with" or visa versa changes the meaning of the function?

-----

4 points by absz 5827 days ago | link

You yourself gave an example. The fact that Arc allows destructuring (that is, writing (let (a b) lst ...)) means that the presence of a list is not an adequate indicator of whether you're letting or withing. And without that, how do you know when you're done defining variables? If you don't parenthesize them, they could go on forever. The only other option is to remove the implicit do in let/with; that way, only the last statement would be run, and the first n would be variable bindings; to run more than one, you would use do.

-----

2 points by bOR_ 5827 days ago | link

Got it :)

  arc> (= b "abba")
  "abba"
  arc> (let (a b) (list 1 2) (pr a b))
  121
  arc> b
  "abba"
  arc> (with (a b) (list 1 2) (pr a b))
  abbaabba"abba"
  arc>

-----

3 points by eds 5827 days ago | link

Yes, you can, but you might have to sacrifice the implicit 'do block in 'let. See http://arclanguage.org/item?id=3234.

That said, it might be good to remove the implicit 'do anyways, since as pg has said, an explicit 'do highlights non-functional code. Combining 'let and 'with would just be a convenient side effect.

P.S. If I am not mistaken I think this would also allow you to do destructuring as well...

-----

3 points by absz 5826 days ago | link

This is actually fairly simple to write (first defining butlast for convenience):

  (def butlast (seq)
    " Returns every element of `seq' but the last one.
      See also [[last]] [[cut]] "
    (cut seq 0 -1))
  
  (mac letn parms
    " Simultaneously ssigns the given (unparenthesized) local variables in the
      one-statement body.
      See also [[let]] [[with]] [[letns]]"
    `(with ,(butlast parms) ,(last parms)))
  
  (mac letns parms
    " Sequentially assigns the given (unparenthesized) local variables in the
      one-statement body.
      See also [[let]] [[with]] [[letn]]"
    `(withs ,(butlast parms) ,(last parms)))
Then letn is like with, but unparenthesized, and letns is like withs, but unparenthesized. (letn = "let n variables".) And yes, destructuring works.

-----

2 points by eds 5826 days ago | link

Perhaps these should be added to Anarki?

-----

1 point by absz 5826 days ago | link

Probably would make sense, but I'd rather wait until we had better names (I don't particularly like these.) Thoughts?

-----

2 points by almkglor 5824 days ago | link

'where ?

  (where foo (some-expression)
         bar (hmm that)
    (some-fn foo bar))

  (wheres val    (another-expression)
          grind  (grr val)
    (that-fn val grind))

-----

3 points by absz 5824 days ago | link

That's not bad... given?

  (given s1 (zebda oualalaradime)
         s2 (cake  symphony in c)
    (play s1 s2))
  
  (givens arc (language-by             pg)
          mzs (implementation-language arc)
    (run-in arc mzs))

-----

3 points by skenney26 5824 days ago | link

Okay, for some reason I can't get this out of my head.

What if "let" becomes "as", given becomes "let", and givens becomes "lets"?

-----

1 point by absz 5824 days ago | link

I would be reluctant to change let, since it's a standard operation in arcN.tar. Otherwise, there's probably some merit to that.

-----

3 points by eds 5824 days ago | link

And now we're back to waiting for pg to do something ;)

-----

1 point by almkglor 5824 days ago | link

Heck no. We can do this ourselves. Remember, the textual transformation to transform let's is just that: a textual translation. It should be possible to create an automated translation tool (based off raymyers' treeparse) that will handle this for us.

Let the old version of 'let be Arc2Let, and the proposed new let be Arc2.7Let. Let the old version of 'with and 'withs be Arc2With and Arc2Withs, respectively. We need to determine if each Arc2Let in the source is composed of a single expression in the body. If it is, we leave it as-is. If it isn't, we simply replace it with Arc2.7As.

For each Arc2With we determine if the body is composed of a single expression. If it is, we replace it with Arc2.7Let, removing the parens around the Arc2With bindings. If it isn't, we leave it as-is. Ditto for Arc2Withs, replacing it with Arc2.7Lets.

We define an expression simply as a sequence of whitespace, base-expression, and whitespace. We define whitespace as being either a comment (either #||# or ;) or ordinary whitespace.

A base-expression is simply a symbol, a number, a character, a string, a quote-expression, a comma and comma-at expression, or a list. A quote-expression is simply the ' quote or ` backquote character followed by maybe whitespace, followed by an expression; comma and comma-at are defined similarly. A list is composed of an opening parenthesis followed by many expressions, followed by a closing parens.

We can determine if a 'let form has several expressions by defining two variants of a 'let form. An Arc2Let is composed of ( <maybe whitespace> let <whitespace> <expression> <expression> <expression> [many <expression>]), and that we have to transform to Arc2.7As (by filtering out the let expression using treeparse 'filt). An Arc2.7LetCompatible is composed of just (let <expression> <expression> <expression>), which we do not transform.

----

Of course, this does represent a veritable fork of the Arc code ^^.

-----

1 point by absz 5824 days ago | link

I would leave with and withs alone, so that we have the option of the implicit do (also because it makes it easier to implement given/Anarki-let :P). And why not use a code-tree-walker if we want to do this—isn't that the point of Lisp?

Still, I don't quite think the fork is worth it….

-----

2 points by almkglor 5823 days ago | link

Actually the point of messing with the existing 'with / 'withs is to force the programmer to consider using the new form of 'let. ^^

The problem of using a code-tree walker is: you lose the comments, which are arguably about 50% the value of the code.

-----

1 point by absz 5823 days ago | link

Right, comments. Just a little important, aren't they? :P

You raise a good point... it's the same number of parentheses either way. But in that case, why not just have let and lets (as given(s)), and be done with it?

-----

3 points by almkglor 5823 days ago | link

> let and lets (as given(s))

Done and on the git ^^

Edit: as an aside, given that pg has said that he'll modify Arc as if there's nobody else programming in it, and that he does not appear to be using Anarki, eventually when Arc3 does come around, it is very possible that Anarki will be incompatible with Arc3. We may very well need to build a converter program in the future to transform Arc2-base Anarki to Arc3-base Anarki, so my abstract nonsense may very well be necessary in the future.

-----

1 point by absz 5823 days ago | link

Thanks!

And general abstract nonsense is almost always a good thing... still, that is worrisome.

-----

1 point by almkglor 5824 days ago | link

'given looks good - I think it's better than 'where.

-----

1 point by almkglor 5826 days ago | link

'these?

  (these x y
         r v
    (foo x r))
Of course it turns into 'theses ....

-----

2 points by skenney26 5825 days ago | link

Interesting idea. I like "as".

-----

2 points by almkglor 5825 days ago | link

  (as var x
      foo 42
    (something var foo))
Hmm...

But how about withs ?? == ass? ^^

-----

1 point by skenney26 5824 days ago | link

Think of it as short for assign :)

-----

1 point by skenney26 5824 days ago | link

How about "as" and "az"?

-----

5 points by absz 5816 days ago | link

I've been programming with given(s) for a little while now, and I really like it. Can't say why I'm so vehement, but it's definitely a Good Thing™. Thank you for bringing this up again (and a "thank you" to aidenn0, if he/she is still reading these fora, for suggesting this in the first place).

-----

3 points by almkglor 5816 days ago | link

An interesting bit about 'givens is that it makes functional programming in an imperative style almost seamless:

  (givens f (car n)
          v f!v
          _ (prn v) ; v isn't being set properly in some cases for some reason...
          l (combinatorics f v)
          _ (prn l) ; debugprint
    (is l 'undef))

-----

2 points by bOR_ 5816 days ago | link

I'm not on anarki, but I've followed this discussion. If you use given rather than let and with, which of the two options below would come out?

arc> (= b "abba") "abba" arc> (let (a b) (list 1 2) (pr a b)) 121 arc> b "abba" arc> (with (a b) (list 1 2) (pr a b)) abbaabba"abba" arc>

-----

2 points by absz 5816 days ago | link

  arc> (given (a b) (list 1 2)
         (pr a b))
  121
The difference between given and let/with is that you cannot have more than one statement in the body of the given. For instance:

  arc> (given (a b) (list 1 2)
         (prn "Here")
         (pr a b))
  Error: "Can't understand fn arg list \"Here\""
What's happening here is that given is trying to bind (prn "Here") to (pr a b), but (naturally) can't bind a string; it takes the first n args, where n is the largest even number less than or equal to the number of arguments provided, and interprets them as variables. You must, therefore, write

  arc> (given (a b) (list 1 2)
         (do
           (prn "Here")
           (pr a b))
  Here
  121
.

Also, I highly recommend switching to Anarki. It's got bugfixes and enhancements galore (and even runs on the newest version of mzscheme).

-----

4 points by bOR_ 5815 days ago | link

So the main drawback of given is that you need to make your do explicit? mmm, I never liked it implicitly anyway ;).

-----

3 points by absz 5815 days ago | link

It's the only "drawback", if such it is. I feel that since you need extra parentheses for either the body or the variables, it's better to wrap the body in a do, since that's less common.

-----