15
$\begingroup$

There are some functions for which an operator form would make sense but isn't implemented. For example, I'd like to make this work:

RandomSample[3] @ Range[10] 

You can do something like this:

Unprotect[RandomSample]; Off[RandomSample::lrwl]
RandomSample[n_][x_] := RandomSample[x, n]

But I wonder if there is a standard technique to define operator forms for system functions?

$\endgroup$
8
  • 1
    $\begingroup$ I take it you would not find RandomSample[#, 3] &[Range[10]] to be satisfying. In any case, a very good question. $\endgroup$
    – bbgodfrey
    Apr 18, 2016 at 5:14
  • 4
    $\begingroup$ How about Infix notation? It looks nice for your example: Range[10]~RandomSample~3. No need to Unprotect anything. $\endgroup$
    – Jens
    Apr 18, 2016 at 6:02
  • 1
    $\begingroup$ You can find more function run EntityList[EntityClass["WolframLanguageSymbol","Curryable"]] $\endgroup$
    – yode
    Apr 18, 2016 at 7:46
  • $\begingroup$ @yode that's a nice feature! $\endgroup$
    – M.R.
    Apr 18, 2016 at 8:25
  • $\begingroup$ The answer to this question is NO. There is no standard way of defining operator forms of a built-in function short of Unprotecting and defining one yourself or hoping that in a future release Wolfram Inc. would include one. $\endgroup$
    – RunnyKine
    Apr 18, 2016 at 16:01

2 Answers 2

7
$\begingroup$

A true operator would use SubValues but here's a position-coded pseudo-operator form "constructor" using UpValues that can be applied to most or all system functions:

\[Bullet] /: h_[pre___, \[Bullet], post___] := 
  Function[expr, h[pre, expr, post]];

For example,

Dataset[{a, b, d, c}][
  Partition[\[Bullet], 2] /*  
   MapIndexed[Rule, \[Bullet], {2}]] // Normal

{{a->{1,1},b->{1,2}},{d->{2,1},c->{2,2}}}

• Could not use SubValues with this definition - too deep for evaluator.

• Position coding enables options or other parameters (only Map and a few other system functions allow this). This is also useful for functions like MemberQ where one might operate on either the first or second slot.

• It uses Bullet because it looks nice and takes only 2 chars to input: Alt-8 (ideally, one should be able to type two commas in a row to represent the desired slot, but overloading Null doesn't work).

• Though it seems it only saves one character compared to #...& Function syntax, it also avoids parentheses when combined with RightComposition as in the above example: ... /* (MapIndexed[Rule,#, {2}]&).

$\endgroup$
1
  • 2
    $\begingroup$ Very nice! A possible slight improvement: \[Bullet] /: h_[pre___, \[Bullet], post___] := Function[, h[pre, ##, post], {HoldAll}] This allows you to splice in arbitrarily many arguments and also Holds them so that the Hold related attributes of f can kick in (however, both these "features" are not supported for the built-in operator forms, so this might confuse the user) $\endgroup$
    – Lukas Lang
    Sep 8, 2017 at 16:38
6
$\begingroup$

Since there was no objection to my comment, I'll post it as an answer:

By using Infix notation, an operators with arbitrarily many arguments (more than one) can be written as in this example:

Range[10]~RandomSample~3

So the operator separates the arguments in the input.

If, on the other hand, you want to actually use a re-defined version of the built-in operator in your programming, then the answer would be different. A custom operator for a system function can always be defined as below:

randomSample[n_] := Function[list, RandomSample[list, n]]

rs = randomSample[3]

(* ==> Function[list$, RandomSample[list$, 3]] *)

rs[Range[10]]

(* ==> {6, 2, 3} *)

randomSample[3][Range[10]]

(* ==> {8, 2, 10} *)
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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