3
$\begingroup$

Consider this example from the Wolfram Documentation:

Thread[f[{a, b, c}, x]] 

{f[a, x], f[b, x], f[c, x]}

Now, let's modify the list:

Thread[f[{{a, b}, {c, d}, {e, f}}, x]] 

{f[{a, b}, x], f[{c, d}, x], f[{e, f}, x]}

, which is the way I expected it to work.

However, the following works unexpectedly:

f1[inp1_, inp2_] := Join[inp1, {inp2}]; Thread[f1[{{a, b}, {c, d}, {e, f}}, x]] 

{{a, c, e, x}, {b, d, f, x}}

Questions:

  1. Why? I'm obviously missing something;
  2. How do I make f1[] to behave as expected from the WD example?
$\endgroup$
6
  • 1
    $\begingroup$ I do not see anything unexpected, Evaluate jo = Join[{{a, b}, {c, d}, {e, f}}, {x}]; Thread[jo] $\endgroup$ Commented Sep 14 at 14:58
  • 1
    $\begingroup$ Use Trace to see the evaluation order. Thread does not have any hold attributes, which means that f1 is evaluated first, and only then Thread comes into play. $\endgroup$ Commented Sep 14 at 14:59
  • $\begingroup$ You can use f1[inp1_, inp2_] := Join[inp1, inp2]; Thread[f1[{{a, b}, {c, d}, {e, f}}, x]] /. x -> {x} to have your expected output. $\endgroup$ Commented Sep 14 at 15:03
  • $\begingroup$ Hopefully a simple example... compare these two: (1) Thread[f[{{a, b}, {c, d}, {e, g}}, x]] and (2) Thread[f[{a, b}, {c, d}, {e, g}, x]]. Note the different structure of the arguments to f. So you shouldn't expect the same output. $\endgroup$ Commented Sep 14 at 15:03
  • 1
    $\begingroup$ As Wagner (p 109) succinctly points out. "There is one caveat about using Thread, however. It evaluates its arguments before doing the threading". And "Here is a trick for getting around this type of problem that every Mathematica programmer should know about: Unevaluated may be wrapped around any argument to a function to pass the unevaluated form of the argument to the function" For example (Wagner) Thread[Unevaluated[Equal[{1, 2, 3}, {1, 2, 4}]]] (as @Michael E2 has pointed out in a comment for the OP example) $\endgroup$ Commented Sep 16 at 11:06

1 Answer 1

6
$\begingroup$

Your first question is that you're probably missing how the sequence of evaluation occurs, specifically that the expression f1[{{a, b}, {c, d}, {e, f}}, x] will be evaluated before the rules for Thread are applied. I.e. Thread[f1[{{a, b}, {c, d}, {e, f}}, x]] evaluates to Thread[{{a, b}, {c, d}, {e, f}, x}] before continuing on to result in {{a, c, e, x}, {b, d, f, x}}.

As for your second question, I'll need to make some assumptions about how you're getting to this point in your program. Since you're trying to evaluate this expression:

Thread[f1[{{a, b}, {c, d}, {e, f}}, x]] 

then you must at some point have been able to assemble your desired arguments {{a, b}, {c, d}, {e, f}} and x already. So, you could just as easily have put them together in a list:

{{{a, b}, {c, d}, {e, f}}, x} 

If you can do that, then all you need to do now is use MapApply after Threading:

f1 @@@ Thread[{{{a, b}, {c, d}, {e, f}}, x}] (* {{a, b, x}, {c, d, x}, {e, f, x}} *) 

(Assuming your definition for f1)

If for some reason you really want the f1 in your structure prior to Threading, then you could first inactivate it and then activate it afterward:

Thread[Inactive[f1][{{a, b}, {c, d}, {e, f}}, x]] // Activate 

If we knew more about the provenance of your individual arguments, we might have more suggestions.

$\endgroup$
3
  • 4
    $\begingroup$ The pre-Inactivate idiom: Thread[Unevaluated@f1[{{a, b}, {c, d}, {e, f}}, x]]. $\endgroup$ Commented Sep 14 at 16:14
  • $\begingroup$ Now I know, thx. $\endgroup$ Commented Sep 15 at 10:56
  • $\begingroup$ ReleaseHold@Thread[Hold[f1][{{a, b}, {c, d}, {e, f}}, x]], too. $\endgroup$ Commented Sep 15 at 12:15

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.