Is there any way to implement a "sequential" With[] in Mathematica?

3

I want the equivalent of Scheme's let*, or basically, a sequential With that works like this:

With[{a = 0,
      a = a + 1,
      a = a + 1},
      a]

Is there any way to implement this? Everything I tried with Hold/Unevaluated/etc. led nowhere.

user541686

Posted 2016-03-07T10:07:00.020

Reputation: 1 257

Question was closed 2016-03-07T13:13:22.820

1

Interesting v10: https://www.wolfram.com/mathematica/new-in-10/inactive-objects/transform-code.html

– unlikely – 2016-03-07T10:11:56.657

13Add bracing for each level. In Mathematica 10.something we started to allow this. `In[655]:= With[{a = 0}, {a = a + 1}, {a = a + 1}, a]

Out[655]= 2`. There is some amount of reddening in the user interface because it has not yet caught up to this change (fixing that is not entirely trivial). – Daniel Lichtblau – 2016-03-07T16:48:13.897

1@DanielLichtblau: Thanks a lot for mentioning that, But ouch, that red is nasty! Any idea when it might get fixed? I actually use the syntax highlighting to help me figure out what variables are declared properly... – user541686 – 2016-03-07T19:19:25.493

@unlikely: Thanks a ton for the links, those are super helpful! – user541686 – 2016-03-07T19:20:03.290

I wish I knew, but I don't. And I agree the highlighting is useful, especially when it works as expected. – Daniel Lichtblau – 2016-03-07T19:21:35.980

@DanielLichtblau This is interesting. What is the relationship betwen this construct, IterateWith and LetL of the link I provided? I.e. it is equivalent to something else? (I recently encountered a problem with IterateWith I don't remember...) – unlikely – 2016-03-07T20:00:30.053

@unlikely: When I just tried the code on Wolfram's site that you linked to, it broke on some of my code. But I found an elegant way to fix it and make it work with other things to -- I'll post an answer on the duplicate! – user541686 – 2016-03-07T20:28:52.127

@unlikely Offhand I'd say it is most similar to BetterWith from that MSE link. – Daniel Lichtblau – 2016-03-07T21:48:01.973

@DanielLichtblau: Thanks for the response! PS, I think I found a nasty bug you may want to look at.

– user541686 – 2016-03-08T06:55:16.753

Under Preferences > Appearance > Syntax Coloring > Errors and Warnings, I unchecked "Excess arguments" because I can't live with all that red. This is a more surgical alternative to turning off all syntax coloring. – Bezewy – 2019-11-25T21:41:58.460

Answers

6

This is outside the scope of With. The documentation says:

With[{x=x₀, y=y₀, ...}, expr]

specifies that all occurrences of the symbols x, y, ... in expr should be replaced by x₀, y₀, ...

So even if there was a "sequential" With, it wouldn't be able to understand a = a+1 as updating the value of a. It would always just be a replace rule.

I think you'd be best off with a Module:

Module[{a},
  a = 0;
  a = a+1;
  a = a+1;
  a]

You can write your own command which rewrites the form of the command for you, for example:

letstar[init_List, expr_] :=
  With[{vars = symbols[init]}, 
    Module[vars, CompoundExpression @@ Join[init, {expr}]]]
symbols[init_List] := Union@Hold[init][[1, All, 1]]
SetAttributes[symbols, HoldFirst]
SetAttributes[letstar, HoldFirst]

This assumes that the first argument of letstar is a list of assignments (this is not checked) and holds its form so that they are not performed. Instead, they are passed to symbols which only extracts the left-hand sides and lists unique variables appearing in them. This is passed to a Module as the local variables, the init block is converted into a compound expression and finally expr is evaluated. So if you call

letstar[{a = 0, a = a + 1, a = a + 1}, a]

this gets internally transformed to

Module[{a}, a = 0; a = a+1; a = a+1; a]

and returns

2

The Vee

Posted 2016-03-07T10:07:00.020

Reputation: 1 720