8

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

theorist
  • 3,633
  • 1
  • 15
  • 27
  • 8
    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) – Lukas Lang Jul 05 '21 at 08:01
  • 3
    ..., i. e., AllTrue[{2, 6, 8, 4}, x |-> x <#] & @ 10. – kglr Jul 05 '21 at 08:10
  • 3
    Or Function[n, AllTrue[{2, 6, 8, 4}, # < n &]] or if you prefer more verbose code. – Sjoerd Smit Jul 05 '21 at 08:23
  • 2
    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})? – user1066 Jul 05 '21 at 08:33
  • Thanks everyone. As an alternative to, say, f[n_] := AllTrue[First /@ FactorInteger@n, #∣(n/# - 1) &]; f[30], why does Function[n, AllTrue[First /@ FactorInteger@n, #∣(n/# - 1) &]]@30 work, but AllTrue[First /@ FactorInteger@#, (n |-> n)∣(#/(n |-> n) - 1)] &@30 does not? – theorist Jul 05 '21 at 08:38
  • 1
    @theorist Because (n |-> n)∣(#/(n |-> n) - 1) asks for the divisibility of two functions, which is not defined. Check InputForm[AllTrue[First /@ FactorInteger@#, (n |-> n)\[Divides](#/(n |-> n) - 1)] &] to see what goes wrong. – Sjoerd Smit Jul 05 '21 at 09:11
  • @SjoerdSmit Well yes, but I was asking why that doesn't work. I thought, from kglr's example, that the principle was one substitutes x |-> x (or whatever variable you please) for #, since that effectively says "this argument is used internally", and then substitutes # for n to introduce the value from outside. Thus that's what I did with the FactorInteger syntax. But that doesn't work in that case. Perhaps if you could give me the correct non-verbose syntax (i.e., using n |-> n) for that example, I could better understand the underlying concept. – theorist Jul 05 '21 at 09:20
  • 4
    @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. – Sjoerd Smit Jul 05 '21 at 09:24
  • @theorist Oh, and one more thing: the notation x -> x^2 is short for Function[x, x^2]. That's what it means, just to be clear on that. – Sjoerd Smit Jul 05 '21 at 09:30
  • @SjoerdSmit Did you perhaps instead mean to write "x |-> x^2 is short for Function[x, x^2]"? I ask because it's my understanding that -> means "Rule" and |-> means "Function". And thanks for your expanations—they look like they'll be very helpful in aiding my understanding; I'll review them tomorrow. – theorist Jul 05 '21 at 09:47
  • @theorist Ah, yes. You're right. I mistyped it. It should have been x |-> x^2. – Sjoerd Smit Jul 05 '21 at 10:08
  • 1
    I am not fully sure of my ground here, but on reading this post by wreach, AllTrue[{2, 6, 8, 4}, CurryApplied[#2<# &,2][#]]& @ 10 (* True *). For example, AllTrue[{2, 6, 8, 4}, CurryApplied[#2<# &,2][#]]& /@ {8,10} (* False, True *). In addition, AllTrue[{2, 6, 8, 4}, OperatorApplied[#2<# &,2][#]]& @ 10 – user1066 Jul 05 '21 at 10:49
  • 1
    Just for fun: AllTrue[First/@FactorInteger[#], CurryApplied[#2∣(#1/#2 - 1)&,2][#]]&/@Range[30] – user1066 Jul 05 '21 at 12:32
  • @SjoerdSmit As an exercise, I've tried using |-> in other applications where I need to avoid variable collision, but can't figure out how to make it work here, even after looking at its FullForm: rf = {{6, 3}, {3, 5}, {0, 2}, {3, 0}}; (r = #; Mean@r - # & /@ r) &@rf. I was wondering if you might be able to tell me what would be the equivalent syntax with |->. – theorist Jul 20 '21 at 07:28
  • You mean like (r |-> Mean[r] - # & /@ r) @ rf? – Sjoerd Smit Jul 20 '21 at 11:57
  • @SjoerdSmit Yes, thanks! With that last example, I think I'm starting to see a pattern in how this works. For instance, with AllTrue[{2, 6, 8, 4}, n |-> n < #] &@10 $\equiv$ AllTrue[{2, 6, 8, 4}, Function[n, n < #]] &@10, the external argument (10) is fed to #, and the local variable (n) is used to create an internal function that takes each successive element of {2,4,6,8} and compares it with 10. By contrast, with (r |-> Mean@r - # & /@ r)@rf $\equiv$ (Function[r, Mean@r - # & /@ r])@rf, the & after the # indicates the # is being used internally for a pure function, and – theorist Jul 21 '21 at 04:33
  • ...thus the external argument (rf) is fed into the local variable (r) instead of to #. Alas, I tried applying this to a somewhat more complicated problem, in which I have two external arguments, but was unable to see how to use the |-> syntax there: (a = #1; b = #2 ; AllTrue[a, # < b &]) & @@ {{2, 4, 6, 8}, 10}. If you wouldn't mind, I'd be very interested to see how one would construct that using |->. Also, might you happen to know anywhere I could find a tutorial on this? Wolfram's documentation doesn't seem to cover this type of use of Function. – theorist Jul 21 '21 at 04:38
  • 1
    @theorist: ({a, b} |-> AllTrue[a, # < b &]) @@ {{2, 4, 6, 8}, 10}. It's described (tersely) at the top of the doc page of Function. – Sjoerd Smit Jul 21 '21 at 06:17

1 Answers1

12

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} *)

Leonid Shifrin
  • 114,335
  • 15
  • 329
  • 420
  • 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? – theorist Jul 07 '21 at 22:59
  • 2
    @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. – Leonid Shifrin Jul 08 '21 at 13:20