1
$\begingroup$

It is possible to define my own With construct where each local constant can depend on the previous defined local constants?

I wish to replace something like this

With[{m=10},
  With[{h=1/m},
    Table[{i h}, {i, 0, m}]
  ]
]

with something like this

WithMany[{m=10, h=1/m},
    Table[{i h}, {i, 0, m}]
]

The very basic idea is to use Fold:

Attributes[WithMany] := {HoldAll};
WithMany[{vars___}, body_] := Fold[With[{#2}, #1] &, body, {vars}]

but we need to properly evaluate the argumens in a non-standard way, possibly using Hold and related constructs. I'm not so fluent with this.

An improvement would be to use the minimum number of With constructs depending on the dependencies between variables.

Any help will be appreciated.

EDIT As several people pointed out the original question has already been answered. This solve my immediate needs but I'm still interested to other implementation.

@Leonid Shifrin think the referred answer already use the best approach, the simplest, the most elegant, the most efficient and so, but, even if true, I consider an interesting programming exercise to try different approach, like the one in my original question, using functional programming and Fold

The sketch of a possible implementation is the following:

Attributes[WithMany] := {HoldAll};
WithMany[vars : {__}, body_] :=
 Block[{With},
  Attributes[With] = {HoldAll};
  ReleaseHold@Fold[
    With[{#2}, #1] &,
    Hold[body],
    Reverse@Thread@Hold@vars
    ]
  ]

I don't understand if there is some limit or issue with this implementation, or if it is fully equivalent to the one in the referred answer and to nested With costruct (after adding Syntax coloring and handling SetDelayed)?

At a first sight I like more my approach (if it works properly of course) and I think is cleaner. It also appears slightly faster, according to some very basic tests. But I recognize that some people might prefer a different approach.

$\endgroup$
8
  • $\begingroup$ I don't fully understand the referred answer, but, apparently we make use of a recursive definition. There is a way to avoid and make a one-time direct replacement? $\endgroup$
    – unlikely
    Jul 2, 2014 at 16:52
  • 1
    $\begingroup$ Yes, there is, but this will be less natural / harder / less elegant. Since the resulting code expansion is a nested With, recursion is IMO the most natural road to proceed here. $\endgroup$ Jul 2, 2014 at 16:55
  • $\begingroup$ Fold is a construct for implementing recursion without the need of spreading the definition of a construct across multiple rules. IMO, if usable here, is better. So I edited the question to investigate this approach... $\endgroup$
    – unlikely
    Jul 2, 2014 at 22:57
  • 1
    $\begingroup$ This is not a simple recursion, it is combined with evaluation control. In other words, it is recursive code generation, and you have to think about evaluation. I see absolutely no advantage in using Fold here, but at the point where you start being interested not in just having a solution to the problem, but having it in a specific way, it all becomes speculative. So, in this new formulation I'd consider this either opinion-based, or too narrow. Technically, I don't see here anything deeper than just another exercise in evaluation control. But may be I am wrong. Let's see what others think. $\endgroup$ Jul 2, 2014 at 23:03
  • $\begingroup$ Also, technically, Fold does not implement recursion. It actually does the opposite - it kills it, for a rather small subset of all cases where recursion can be used. There are lots of more complex cases where recursion can not be reduced to Fold. And I personally view recursion cleaner and more idiomatic, in lots of cases. And, as I said, strictly more powerful than Fold. This is not to say that I don't appreciate Fold - if you look at the code I posted on this site, you'll see that I use Fold rather frequently. $\endgroup$ Jul 2, 2014 at 23:09

1 Answer 1

3
$\begingroup$

I don't know who to credit or where I picked it up, but there is an undocumented form of With:

With[{m = 10}, {h = 1/m}, Table[{i h}, {i, 0, m}]]

That's very close to what you're after. However, the syntax coloring for this form is messed up.

$\endgroup$
2
  • 1
    $\begingroup$ The syntax colouring can at least be somewhat ameliorated to the point of being palatable by turning off its "HighlightExcessArguments" option. FWIW I also don't regard this issue as being "solved" until it becomes a standard, documented part of the language, which, kind of unbelievably, remains the case today. $\endgroup$ May 19 at 2:45
  • $\begingroup$ Daniel Lichtblau has confirmed that this undocumented syntax for With is not going away, at least. $\endgroup$ May 19 at 3:11

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.