15

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?

M.R.
  • 31,425
  • 8
  • 90
  • 281
  • 1
    I take it you would not find RandomSample[#, 3] &[Range[10]] to be satisfying. In any case, a very good question. – bbgodfrey Apr 18 '16 at 05:14
  • 4
    How about Infix notation? It looks nice for your example: Range[10]~RandomSample~3. No need to Unprotect anything. – Jens Apr 18 '16 at 06:02
  • 1
    You can find more function run EntityList[EntityClass["WolframLanguageSymbol","Curryable"]] – yode Apr 18 '16 at 07:46
  • @yode that's a nice feature! – M.R. Apr 18 '16 at 08:25
  • 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. – RunnyKine Apr 18 '16 at 16:01
  • @Jens, infix works in that case but not with more general pipelines, eg using RightComposition – alancalvitti Dec 08 '16 at 18:33
  • @RunnyKine, can you clarify what you mean by "no standard way" - are there non-standard ways, eg via pattern manipulation? – alancalvitti Dec 08 '16 at 18:35
  • @alancalvitti To be fair, he did not explicitly ask for a method that works for all system functions. The only standard technique that could work without exceptions is to define your own named function, but that's trivial. – Jens Dec 08 '16 at 18:41

2 Answers2

7

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}]&).

alancalvitti
  • 15,143
  • 3
  • 27
  • 92
  • 2
    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) – Lukas Lang Sep 08 '17 at 16:38
6

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} *)
Jens
  • 97,245
  • 7
  • 213
  • 499