11
$\begingroup$

Suppose that I have a function that has two patterns:

disksConstantRadius[radius_][points_] := Disk[#, radius] & /@ points

(noting that this would be better---but less readable---as)

disksConstantRadii[radius_?NumericQ][points_ /; ArrayQ[points, 2,NumericQ]] := 
 Disk[#, radius] & /@ points

The above works just fine.

The objective is to make an operator form of Disk that operates on a list of points, but the question is more general.

Is there a name for this construction f[][]??

This is just idle curiosity (I clearly have a work-around), but would it be possible to make the function be Listable in its second argument?

I'm not surprised that this

Clear[disksConstantRadius];
Attributes[disksConstantRadius] = {Listable}
disksConstantRadius[radius_?NumericQ][{x_, y_}] := 
 Disk[{x, y}, radius]

doesn't work.

And also not surprised that this:

Clear[disksConstantRadius];
Attributes[disksConstantRadius[_]] = {Listable}
disksConstantRadius[radius_?NumericQ][{x_, y_}] := 
 Disk[{x, y}, radius]

doesn't work either.

How could one construct an operator form disksConstantRadius[radius]?

There is a nice discussion about Listable here: The role and meaning of Listable, Leonid Shifrin, 2013

$\endgroup$
4
  • $\begingroup$ "Listable" works for any nesting depth. That means your function would act on every coordinate separately. Therefore, you do not want a function, that should take a vector (e.g. a point) as input, to be listable. The way to go is using "Map" $\endgroup$ Aug 19, 2022 at 10:03
  • $\begingroup$ The Map method is embodied in the first two examples which works just fine. Another solution is diskConstantRadii[r_] :=diskConstantRadii[r]= Compile[{{p,_Real,1}}, Evaluate[Disk[{Indexed[p,1].Indexed[p,1]},r],Attributes->Listable]. I’m just curious how one might do the f[][] version programmaticaly. My goal is to learn a new tick. $\endgroup$ Aug 19, 2022 at 10:43
  • $\begingroup$ Edit, above comment should be {Indexed[p,1],Indexed[p,2]} $\endgroup$ Aug 19, 2022 at 10:49
  • $\begingroup$ You can't make f listable if the basic call has the form f[{x_, y_}]. If f is listable, then f[{x, y}] becomes {f[x], f[y]} before any definitions for f are applied. It doesn't matter whether f is a symbol or a head like disksConstantRadius[r]. It can't be done via Listable. The restriction on subvalues is a red herring, and you have to use Map or Thread. $\endgroup$
    – Michael E2
    Aug 20, 2022 at 14:34

2 Answers 2

7
$\begingroup$

Here's an alternative to Listable. It's somewhat the opposite to Listable, but it's also the opposite to unlistable. More like relistable: If given a simple list, change it to a list of lists.

ClearAll[disksConstantRadius];
disksConstantRadius[radius_?NumericQ][p_?VectorQ] /;
    Length@p == 2 := 
  disksConstantRadius[radius][{p}];
disksConstantRadius[radius_?NumericQ][pts_?MatrixQ] /; 
    Last@Dimensions@pts == 2 :=
  Thread[Disk[pts, radius]];

The conditions Length@p == 2 and Last@Dimensions@pts == 2 are somewhat optional depending on where you want the function call to fail, if it is called with data that are not coordinates of points in the plane.

Example:

disksConstantRadius[1][RandomReal[1, {3, 2}]]
(*
  {Disk[{0.631657, 0.646406}, 1],
   Disk[{0.223139, 0.962916}, 1], 
   Disk[{0.260601, 0.75212}, 1]}
*)

One thing that differs with the OP's description of the function is that disksConstantRadius always gives a list of disks, which might be an advantage in dealing with its output.

disksConstantRadius[1][{3, 7}]
(*
  {Disk[{3, 7}, 1]}
*)

One might want to add a rule for an empty list, to mimic the standard behavior of Listable functions:

disksConstantRadius[radius_?NumericQ][{}] := {};
$\endgroup$
1
  • $\begingroup$ Clever! Thanks. $\endgroup$ Aug 20, 2022 at 21:39
11
$\begingroup$

A few comments:

$\endgroup$
1
  • 2
    $\begingroup$ I'd probably use f[x_][y_?MatrixQ]... if y is likely to be a medium to large packed array or f will be called a lot. $\endgroup$
    – Michael E2
    Aug 20, 2022 at 14:26

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.