Group Abstract Group Abstract

Message Boards Message Boards

1
|
6.2K Views
|
18 Replies
|
5 Total Likes
View groups...
Share
Share this post:

Understanding named Slot?

Posted 2 years ago

Hello, I feel the pure function is too difficult for me to understand. For example:

Plot3D[Sin[x y], {x, 0, 3}, {y, 0, 3}, ColorFunction -> (Hue[#3/3,.5] &)]

What does the #3 refers to? I know this pure function:

#^2&/@{1,2,3}

as # refers to the 1,2,3 separately. But in the

Plot3D[Sin[x y], {x, 0, 3}, {y, 0, 3}, ColorFunction -> (Hue[#3/3,.5] &)]

there is nothing like {1,2,3}.

POSTED BY: Zhenyu Zeng
18 Replies
Posted 2 years ago

Simple examples of syntax alternatives that produce the same output:

In[1]:= #^2 &[3]
Out[1]= 9

In[2]:= Function[#^2][3]
Out[2]= 9

In[3]:= Function[x, x^2][3]
Out[3]= 9
POSTED BY: Hans Milton

and the new notation : (x |-> x^2)[3]

POSTED BY: l van Veen
Posted 2 years ago

What is the |-> ?

POSTED BY: Zhenyu Zeng
Posted 2 years ago

Yes, I learnt that from you. Thanks.

POSTED BY: Zhenyu Zeng
Posted 2 years ago

Thanks for your help. There are several questions confusing me:

  1. I can understand this MySquare3[x_] := (countUsages += 1; x^2) but what is MySquare3 /@ Range[3]. I think iţ should be MySquare3[#] /@ Range[3]. Why can you mitted the [#]
  2. What is the difference between

    countUsages = 0;
    MySquare3 /@ Range[3];
    countUsages
    (* 3*)
    

and

    countUsages = 0;
    Function[countUsages += 1; #^2] /@ Range[3];
    countUsages
    (* 3 *)

The result is the same as they all ouput 3.

  1. How to tell if there is side effect? Thanks.
POSTED BY: Zhenyu Zeng
Posted 2 years ago

How to tell if there is side effect?

There are two possible questions here. I'll answer both. If you're writing a function, and you want to make sure there are no side effects, then you must make sure that your function references only those variables that are passed in as arguments. If your function reference any other variable, then you have a side effect. This can be tricky if your function references another function, because that function might reference other functions. So, for example, if your function uses RandomInteger (or any of the random functions), then your function has a side effect, because RandomInteger depends on a special system variable. You could "fix" this by using SeedRandom, but then your function won't be random any more. In this case, you just accept the side effect. There might be other subtle ways to create side effects, but referencing non-argument variables is the main way.

The second question is how to tell whether a function that you didn't write but want to use has a side effect. Well, you'd have to inspect the definition of the function and understand it (and the functions that it references) well enough to determine whether side effects exist. And this is the problem with side effects. You may not be able to inspect the function defintion, or the side effect may be subtle. This is why side effects are so pernicious. Unexpected side effects are the cause of many, many software defects.

What is the difference between [MySquare3 and Function[countUsages += 1; #^2]]

Effectively there's no difference. The exact same computations occur. But the process for getting there was slightly different. To evaluate MySquare3[1], the evaluator needed to search the list of DownValues (among other things) for something matching that expression. If it finds something, it will do a replacement. In this case it would have found

HoldPattern[MySquare3[x_]] :> (countUsages += 1; x^2)

and so would have done the replacement to give

countUsages += 1; 1^2

which it would then proceed to evaluate further.

To evaluate Function[countUsages += 1; #^2][1], the evaluator didn't need to go looking for DownValues (or any other type of replacement). It just immediately slurped the argument into the function body to give

countUsages += 1; 1^2

It's the exact same result, just a slightly different path to get there.

what is MySquare3 /@ Range[3] ... why can you omit the [#]

This is just how this syntax is defined. The Map function, aka /@, applies its first argument to every element of the second argument at the first level. So, given a function f and an argument x, the word "apply" means "construct the expression f[x]".

You asked about MySquare3[#] /@ Range[3]. That's a syntactically valid expression--it just doesn't do what you want.

MySquare3[#] /@ Range[3]
(* {(#1^2)[1], (#1^2)[2], (#1^2)[3]} *)

To make this work with slots, you need to use Function:

MySquare3[#] & /@ Range[3]
(* {1, 4, 9} *)

This works, but the Function is superfluous. To evaluate MySquare3[#]&[1], we pull the argument into the body of the function to get MySquare3[1], and now we're right where we would have been had we just started with MySquare3 /@ Range[3].

POSTED BY: Eric Rimbey
Posted 2 years ago

Hello, From your long answer, I learnt a lot. I feel that whether it is a pure function is not important, the more important thing is we make functions to meet our requirements. In many cases, anonymous functions are pure functions, am I right? Thanks.

POSTED BY: Updating Name
Posted 2 years ago
POSTED BY: Eric Rimbey
Posted 2 years ago

Thanks for your explanation. I learnt a lot from it. I will do my best to write pure functions.

POSTED BY: Zhenyu Zeng
Posted 2 years ago

I think this thread has conflated pure and anonymous.

POSTED BY: Eric Rimbey
Posted 2 years ago

Doesn't pure equal anonymous?

POSTED BY: Zhenyu Zeng
Posted 2 years ago

No. Usually when people use "pure" they mean no side effects. They may include other characteristics as well. "Anonymous" means, well, anonymous. That is, an anonymous function is one that is created "on the fly" rather than being retrieved from some variable in the environment.

This expression is an anonymous function:

Function[x, x^2]

That expression in isolation is pretty useless. Once it's evaluated, it's effectively gone (you can reference execution history with %, so that's not strictly speaking true, but practically speaking it's gone). In the following, we're putting an anonymous function to use (presumably we don't expect to use it again later, so we didn't bother giving it a name):

Function[x, x^2] /@ Range[3]

If we did wan't to use it again, we might name it.

MySquare = Function[x, x^2]

Now we can use MySquare and know we're using the exact same function each time. Of course, another functionally equivalent way is this:

MySquare2[x_] := x^2

Side note, the explicit naming of the arguments has nothing to do with a function being anonymous. The following expressions are indeed anonymous, but it's not the absence of "x" that makes them so.

Function[#^2]
#^2&

The following function is not pure:

MySquare3[x_] := (countUsages += 1; x^2)

Incrementing countUsages is a side effect. The following example demonstrates this:

countUsages = 0;
MySquare3 /@ Range[3];
countUsages
(* 3*)

Without inspecting the definition of MySquare3, you wouldn't expect countUsages to change. You can also do this with an anonymous function:

countUsages = 0;
Function[countUsages += 1; #^2] /@ Range[3];
countUsages
(* 3 *)

I should add that, yes, I'm aware the Mathematica documentation often uses "pure" and "anonymous" interchangeably. I find this very strange. The way I justify it to myself is that an expression like MySquare2[x_] := x^2 is actually an assignment of DownValues via SetDelayed, and even though we colloquially say we're defining the MySquare2 "function", we're really defining replacement rules. On the other hand, Function[#^2] is "self-contained", that is, we don't need to look up replacement rules to figure out how to apply it. I think this "stand alone" quality is what the Mathematica documentation is trying to indicate with "pure". I'm not even really speculating, though, as much as I'm grasping at straws to justify this confusing jargon. I'm not even sure I think that is any different than "anonymous".

POSTED BY: Eric Rimbey

Is it still pure if the variables are named?

POSTED BY: Gianluca Gorni
Posted 2 years ago

I don't know. How to know pure more deep?

POSTED BY: Zhenyu Zeng

For Plot3D it refers to the height of the function (the z coordinate). However, by default, it is rescaled from 0 to 1.

POSTED BY: Sander Huisman
Posted 2 years ago

Thanks for your reply. But why the Plot3D[Sin[x y], {x, 0, 3}, {y, 0, 3}, ColorFunction -> Function[{x, y, z}, Hue[z]]] doesn't use pure function? Sometimes it uses pure function, but some times it doesn't.

POSTED BY: Zhenyu Zeng

Function is a pure function, check the documentation.

POSTED BY: Sander Huisman
Posted 2 years ago

Yes. I know now.

POSTED BY: Zhenyu Zeng
Reply to this discussion
Community posts can be styled and formatted using the Markdown syntax.
Reply Preview
Attachments
Remove
or Discard