1

In my code I have

With[
 {
  rowCells=(genCells[#]&/@genSpecs[#])&/@clueRows,
  colCells=(genCells[#]&/@genSpecs[#])&/@clueCols
 },
 While[Not@isDone@Flatten@constraintTable,
    constraintTable=(Thread[f[rowCells,constraintTable]]/.f-> constraintStrip);
    constraintTable=(Thread[f[colCells,constraintTable\[Transpose]]]
                     /.f-> constraintStrip)\[Transpose];
 ]
]

but when I attempt to replace the substitutions for f with

With[
  {
   rowCells=(genCells[#]&/@genSpecs[#])&/@clueRows,
   colCells=(genCells[#]&/@genSpecs[#])&/@clueCols
  },
  While[Not@isDone@Flatten@constraintTable,
    constraintTable=(Thread[constraintStrip[rowCells,constraintTable]]);
    constraintTable=(Thread[constraintStrip[colCells,constraintTable\[Transpose]]]
                       /.f-> constraintStrip)\[Transpose];
  ]
]

I get

Transpose::nmtx: The first two levels of {Transpose[0],Transpose[0],Transpose[0],Transpose[0],Transpose[0],Transpose[0],Transpose[0],Transpose[0],Transpose[0],Transpose[0],Transpose[0],Transpose[0],Transpose[0],Transpose[0],Transpose[0],Transpose[0],Transpose[0],Transpose[0],Transpose[0],Transpose[0],Transpose[0],Transpose[0],Transpose[0],Transpose[0],Transpose[0]} cannot be transposed. >>
Transpose::nmtx: "The first two levels of {Transpose[],Transpose[],Transpose[],Transpose[],Transpose[],Transpose[],Transpose[],Transpose[],Transpose[],Transpose[],Transpose[],Transpose[],Transpose[],Transpose[],Transpose[],Transpose[],Transpose[],Transpose[],Transpose[],Transpose[],Transpose[],Transpose[],Transpose[],Transpose[],Transpose[]} cannot be transposed. \!\(\*ButtonBox[\">>\",

Why do I need to substitute in this way? How can avoid having to do so?


I have a similar issue with

showTable[t_]:=
Grid[
  Join[
    Join[
      ConstantArray["",{9,9},(Style[#,Bold]&/@PadLeft[#,9,""]&/@clueCols)]\[Transpose],
      (Thread[f[(Style[#,Bold]&/@PadLeft[#,9,""]&/@clueRows),
                (t/.cellGraphics)
               ]
    ]/.f->Join)
   ], 
   gridSpecs
];

where a substitution is also required in Thread to avoid errors.

orome
  • 12,819
  • 3
  • 52
  • 100
  • 3
    Thread evaluates its argument before threading, so perhaps the problem comes from evaluating constraintStrip[rowCells,constraintTable]. – Simon Woods Dec 14 '15 at 21:20
  • @SimonWoods: How can it thread over something if it evaluates the whole thing first? – orome Dec 14 '15 at 21:23
  • For many things that's no problem: Thread[{a,b}->{1,2} yields {a->1,b->2}, which is quite useful. – Sjoerd C. de Vries Dec 14 '15 at 21:26
  • 2
    If that is the source of the problem, the question is essentially a duplicate of this one – Simon Woods Dec 14 '15 at 21:27
  • You could Inactivate f. – Sjoerd C. de Vries Dec 14 '15 at 21:27
  • @SimonWoods: And weirdly, (MapThread[constraintStrip, {rowCells,constraintTable}]), which the documentation says is the same thing, works fine. – orome Dec 14 '15 at 21:27
  • @SjoerdC.deVries: I must be missing something. I'm trying to thread constraintStrip over the arguments given; the given arguments themselves don't make sense for constraintStrip, so evaluating it wouldn't work. – orome Dec 14 '15 at 21:29
  • The MapThread documentation contains an example of the difference - Properties & Relations, fourth example. – Simon Woods Dec 14 '15 at 21:33
  • @raxacoricofallapatorius You have constrainStrip defined as a function of two variables and since you provide it with two it evaluates. f is undefined, doesn't evaluate and can then be threaded. – Sjoerd C. de Vries Dec 14 '15 at 21:38
  • @SimonWoods: I guess I don't understand. How can even the third "basic example" in the Thread docs work? Thread[f[{a, b, c}, {x, y, z}]] can't work if f does't take lists arguments, though f[a,x], etc. certainly can. What am I missing. And if the objective is to produce a list of such values (as in the docs, {f[a,x], f[b,y], f[c,z]}, isn't that what Thread is for? – orome Dec 14 '15 at 21:42
  • @SjoerdC.deVries: Wow, this is messed up: Thread[{1,2,3}=={1,2,3}] is True, but Thread[{1,2,3}=={1,c,3}] is {True, False, True} unless is defined, say as c=2, in which case it's True. So the whole structure of the result — in fact, whether any threading even takes place — depends on whether all the components of the arguments can be fully evaluated. Talk about side effects! – orome Dec 14 '15 at 21:57
  • 1
    It's not messed up, {1,2,3}=={1,2,3} evaluates to True - what do you think the result of Thread[True] should be? – Simon Woods Dec 14 '15 at 22:06
  • There have been a few discussions about this. One that I could find is this but there should be more. – Sjoerd C. de Vries Dec 14 '15 at 22:06
  • @SimonWoods: That's not what's messed up. What's messed up is that whether Thread actually threads is contingent on whether every component of the arguments it's meant to thread over can be fully evaluated; if they can, threading will not happen. – orome Dec 14 '15 at 22:12
  • @SjoerdC.deVries: Yes, good link. MapThread is clearly what I should be using, Thread is clearly some other nutty thing that makes no sense. – orome Dec 14 '15 at 22:13
  • I find Thread quite useful. In fact I use it quite a lot to make lists of rules needed to create Associations or Dispatch tables. – Sjoerd C. de Vries Dec 14 '15 at 22:16
  • @SjoerdC.deVries: Understood. But the question isn't whether uses can be found, it's why have Thread provide such uses by not threading (essentially as a side effect). – orome Dec 14 '15 at 22:39

1 Answers1

2

If you want to avoid the substitution, it might be more "elegant" to use MapThread:

MapThread[Join, {colCells, constraintTable\[Transpose]}]

This works like Thread, but Join directly operates on the right arguments.

user8074
  • 1,592
  • 8
  • 7
  • Yes, MapThread gives the expected behavior, but why have Thread behave this way at all? – orome Dec 14 '15 at 23:07
  • @raxacoricofallapatorius Beacause Thread has not attributes like HoldAll and the like, so it first evaluates its arguments, as you can see evaluating Thread[(Print["f"]; f)[(Print["a"]; {a1, a2, a3}), (Print["b"]; {b1, b2, b3})]]. This prints "f", "a" and "b" and then threads f over the two list. – user8074 Dec 14 '15 at 23:15
  • But why have Thread do that? Why have Thread designed to not thread in some cases. – orome Dec 14 '15 at 23:16
  • @raxacoricofallapatorius, the error comes from the effect of Join, not from from the behavior of Thread: when Join evaluates its arguments (before Thread acts, since the evaluations start from the leaves of the expression tree) it produces a single list, with the wrong shape for Thread. The reason why Thread is not holding it's argument should be explained by MMA designers. – user8074 Dec 14 '15 at 23:25
  • I don't think Join comes into play in the first case though, where f is constraintStrip. – orome Dec 14 '15 at 23:28