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.
Answer
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
Comments
Post a Comment