7
$\begingroup$

Here's an example of a pure function:

3^# > 100 &

I can supply any value I please to the function, by placing that value after the prefix. E.g.:

3^# > 100 & @ 8

True

But suppose we have a pure function that already has an argument. E.g., here the argument is {2, 6, 8, 4}:

AllTrue[{2, 6, 8, 4}, # < 10 &]

True

Further suppose I want to create a new pure function that takes the test value in the inequality as an argument. I.e., instead of using a fixed test value (in this case, 10), I want the function to be able to take any test value.

I can accomplish this using a traditional function definition:

f[n_] := AllTrue[{2, 6, 8, 4}, # < n &]
f[10]

True

But is there a simple way to accomplish this entirely with a pure function? In pseudocode, it would look something like this, where the value after the prefix is inserted in place of the ?:

AllTrue[{2, 6, 8, 4}, # < ? &] @ 10

True

$\endgroup$
18
  • 8
    $\begingroup$ You can use Function with named arguments to avoid the collision, e.g (n |-> (#<n&))[10]. (Replace the |-> with \[Function] if you are using an older version) $\endgroup$
    – Lukas Lang
    Jul 5 '21 at 8:01
  • 3
    $\begingroup$ ..., i. e., AllTrue[{2, 6, 8, 4}, x |-> x <#] & @ 10. $\endgroup$
    – kglr
    Jul 5 '21 at 8:10
  • 3
    $\begingroup$ Or Function[n, AllTrue[{2, 6, 8, 4}, # < n &]] or if you prefer more verbose code. $\endgroup$ Jul 5 '21 at 8:23
  • 1
    $\begingroup$ Although not an answer to the general question you ask, for the example you cite you could use AllTrue[{2, 6, 8, 4,11}, LessThan[#]]&[10] (or AllTrue[{2, 6, 8, 4}, LessThan[#]]&/@{10,8})? $\endgroup$
    – user1066
    Jul 5 '21 at 8:33
  • 4
    $\begingroup$ @theorist This is the exact reason I don't like glyphs like |->: it's just not all that clear what they mean to many people. Here's a version of that code that does work: AllTrue[First /@ FactorInteger@#, n |-> n\[Divides](#/n - 1)]&. Be sure to check the InputForm or FullForm of that as well. $\endgroup$ Jul 5 '21 at 9:24
9
$\begingroup$

If you don't want to follow some suggestions made in comments and use the Function with named arguments (and there may be valid reasons to be willing to avoid that), you can use With instead:

fn = With[{n = #}, AllTrue[{2, 6, 8, 4}, # < n &]] &

So that

{fn[5], fn[10]}

(* {False, True} *)
$\endgroup$
2
  • $\begingroup$ I like that construction because of its intuitive nature. Plus it led me to realize it can be written even more simply as: (n = #; AllTrue[{2, 6, 8, 4}, # < n &]) &. Are there examples in which this wouldn't work, and you would need With? $\endgroup$
    – theorist
    Jul 7 '21 at 22:59
  • 2
    $\begingroup$ @theorist Your version introduces n as a global variable, which is generally a bad idea. You could wrap your code in Module (or, in this case, Block), to localize it, like e.g. Block[{n}, (n = #; AllTrue[{2, 6, 8, 4}, # < n &]) &]. But then it essentially becomes the same as using With. Using With seems the cleanest of such methods here, since we know that n is not going to change inside the code. As to examples of failures: in your case, the predicate # < n & is very simple. There could be more complex ones defined separately and referring to global n, which could fail. $\endgroup$ Jul 8 '21 at 13:20

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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