Skip to main content
3 of 4
added 552 characters in body
Mr.Wizard
  • 273.1k
  • 34
  • 595
  • 1.4k

Shotgun thoughts:

  • You don't need the Hold/ReleaseHold pair; Unevaluated will do: Unevaluated[f] /. rules

  • You can use direct destructuring to extract extvar: curvature[f_, range : {var_, __}] :=

  • By extracting var as above you can Block it directly, simplifying everything.

  • You can leave the Table variable out of the main Block as it is already localized.

  • res /. {z_} :> z can replace the line If[Length[res] == 1, res = res[[1]]]; res

  • In fact res can be eliminated and the rule applied to the Table

  • You can pre-evaluate your 1/Sqrt[Total[D[fn,var]^2]] expression; this should be faster, and also eliminates the need for the replacement inside the Table

Putting it together I would write:

SetAttributes[curvature, HoldAll];

curvature[f_, range : {var_, __}] :=
  Block[{var},
    Module[{fn},
      fn = If[ListQ[f], f, {var, f}];
      fn = 1/Sqrt[Total[D[fn, var]^2]];
      Table[fn, range] /. {z_} :> z
    ]
  ]

You will notice red highlighting of var signifying a possible conflict; this is not a problem and is in fact exactly what I desire: the sharing of var between the function, the Block, and the Table.


My answer originally had fn in the Block declaration. This is bad because conceivably fn could appear in the function expression and this would conflict. I have moved it to a Module now.

An alternative is to do without that symbol entirely by writing the lines of code as Functions:

curvature[f_, range : {var_, __}] :=
 Block[{var},
  Table[#, range] /. {z_} :> z &[
   1/Sqrt[Total[D[#, var]^2]] &[
    If[ListQ[f], f, {var, f}]
   ]
  ]
 ]
Mr.Wizard
  • 273.1k
  • 34
  • 595
  • 1.4k