2

Simple input like this

f[x_]:=2x
f[2]

has the predicted output of 4. However, this

r={a->2x};
f[x_] := a/.r
f[2]

Produces the output "2 x". I would like it to produce 4. More generally, is there a way I can incorporate rules into a function definition?

J. M.'s missing motivation
  • 124,525
  • 11
  • 401
  • 574
DJames
  • 187
  • 5
  • 6
    f[x_] = a /. r. – cvgmt Jun 08 '22 at 15:15
  • 2
    it's not a problem with using rules in the def; it's a problem of whether x literally appears in the rhs or not. When applying a definition where the pattern x_ on the lhs has been matched to an argument, e.g. 2, mathematica looks to see if the pattern name x appears anywhere in the definition's rhs, substitutes, then evaluates. Here it only sees a, /., and r, and no x, so it doesn't substitute anything and finishes its application of the definition. All further evaluation "doesn't know about" the definition anymore. Further... – thorimur Jun 09 '22 at 08:17
  • 2
    ...when you use :=, the rhs you typed in is unevaluated, and the definition mathematica learns is the replacement rulef[x_] :> a /. r. When you use =, the rhs is evaluated first, and then learned as a definition—so we start with f[x_] = a /. r, a /. r becomes 2x, then the definition that mathematica learns is the rule f[x_] :> 2x. That's why cvgmt's solution works. See this for more about the difference between := and = :) – thorimur Jun 09 '22 at 08:21
  • @thorimur Please turn your comments into an actual answer! It's obviously too long for a comment, as evidenced by the fact that you had to use two :-) It's great insight into what's going wrong, in addition to how to make it right. – MarcoB Jun 09 '22 at 12:16
  • @MarcoB Haha, you're absolutely right. And thanks! I've turned them into an answer now. :) – thorimur Jun 09 '22 at 23:08

1 Answers1

6

It's not a problem with using rules in the def; it's a problem of whether x literally appears in the rhs or not.

When applying a definition where the pattern x_ on the lhs has been matched to an argument (e.g. 2), Mathematica looks to see if the pattern name x appears anywhere in the definition's rhs, substitutes the matched value for any x's it finds, then evaluates. Here, it looks at f[2] and matches 2 to x_, then looks at the rhs of the definition, and only sees a, /., and r (and no x). So, it doesn't substitute anything, and finishes its application of the definition. All further evaluation (of a /. r) "doesn't know about" the definition anymore. (In particular, it doesn't know about he value 2 that got matched to x, and x is now "just a symbol again".)

Further, when you use :=, the rhs you typed in is unevaluated, and the definition Mathematica learns is the replacement rule f[x_] :> a /. r. However, when you use =, the rhs is evaluated first, and then learned as a definition. So we start with f[x_] = a /. r, a /. r becomes 2x, then the definition that Mathematica learns is the rule f[x_] :> 2x. That's why cvgmt's solution in the comments (f[x_] = a /. r) works. See this for more about the difference between := and = :)

(Note: I omitted some of the technicalities when describing what rule Mathematica actually learns and how it uses the rule, but all in all, it behaves roughly like :>.)

thorimur
  • 9,010
  • 18
  • 32