15

I am trying to modify some code proposed here Part assignment is not a symbol

and I cannot manage to make Flatten work. I write

m = {0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.9, 1.0, 1.5, 1.6}; 
f[list_] := Flatten[Module[{titi = {r, x, y, u, v, n, l, w, s}}, 
  Transpose[{titi, Rest@list}]] /; Length[list] > Length[titi]];

and I get

f[m]

{{r, 0.3}, {x, 0.4}, {y, 0.5}, {u, 0.6}, {v, 0.7}, {n, 0.9}, {l, 1.}, {w, 1.5}, {s, 1.6}}

Alexey Popkov
  • 61,809
  • 7
  • 149
  • 368
Ruth Lazkoz
  • 466
  • 2
  • 8

2 Answers2

16

f[...] := Module[{...}, ... /; condition] is a very special syntax (documented in the Details section of Module). It only works if the right-hand side of the := operator contains a Module. In your example, it contains a Flatten, the Module being buried at a lower level.

What is important to remember is that a /; condition inside of a Module/Block/With must always go together with a := or :>. It is useful to think of /; as going with the := and not with Module.

In fact, normally we write

f[...] /; condition := ...

The reason to use

f[...] := Module[{...}, ... /; condition]

is to be able to use local Module variables in the condition. More precisely, the purpose is to avoid computing things twice. We might need to compute a quantity for the condition, but we may want to use the very same quantity when computing the result of the function. This would not be possible with f[...] /; condition := ....


As @kglr showed, putting the Flatten inside of the Module will fix this.

Szabolcs
  • 234,956
  • 30
  • 623
  • 1,263
  • Wonderful explanation! (Say, we should be able to have memoized, then, functions which occur only under condition, utilizing a form of what we "normally" write within the memoization, yeah?) {checking my understanding, asking for an extension of your answer, if this requires another question to be prosed, I will need to learn fully what I can and cannot "ask" for in a comment!} As always, great work, very clear and understandable! – CA Trevillian May 20 '19 at 11:53
  • Is it correct to say that this phenomena is due to Condition being programmed internally via pattern matching on Module/With/Block and not on f[Module/With/Block]? Is it also correct that this is nowhere mentioned in the docs (I didn't see it anyway)? Is it fair to say that this amounts to a general shortcoming of the entire pattern-matching based programming model? – berniethejet May 20 '19 at 12:41
  • 3
    @berniethejet 1. It's implemented in terms of RuleCondition and $ConditionHold. These are not documented, and I never took the time to fully understand them, but you can search this site to find many discussions. 2. The syntax I described is documented under Details in the Module/Block/With doc pages. It is not widely known, but it's the way to implement the typical error-handling behaviour we see in built-in functions: if something goes wrong, the function does not evaluate. This feature is needed because thing often go wrong late in the processing. 3. I do not see any shortcoming. – Szabolcs May 20 '19 at 12:48
  • Thanks @Szabolcs. I guess what I am trying to say is that for a new user there is no obvious reason why f[...] := Flatten[Module[{...}, ... /; condition]] shouldn't work. It is only once they understand that everything is based on pattern-matching that they can accept these sorts of seemingly arbitrary constraints. – berniethejet May 21 '19 at 16:22
  • 1
    @berniethejet Yes, it's not obvious. I link to think of it as coming from the LHS: f[x_ /; IntegerQ[x]] := ... can be changed to f[x_] /; IntegerQ[x] := ... can be changed to f[x_] := ... /; Integer[Q] (!) can be changed to f[x_] := Module[{}, ...; ... /; IntegerQ[x]]. But there it stops. It does not go deeper. – Szabolcs May 21 '19 at 16:40
10

Put Flatten inside Module:

ClearAll[f]
f[list_] := Module[{titi = {r, x, y, u, v, n, l, w, s}}, 
  Flatten@Transpose[{titi, Rest@list}] /; Length[list] > Length[titi]]

f[m]

{r, 0.3, x, 0.4, y, 0.5, u, 0.6, v, 0.7, n, 0.9, l, 1., w, 1.5, s, 1.6}

You could also use Riffle[titi, Rest@list] instead of Flatten[Transpose[{titi, Rest@list}]].

kglr
  • 394,356
  • 18
  • 477
  • 896