2
$\begingroup$

Recently,I find the program of @J.M. about Get a "step-by-step" evaluation in Mathematica is a very useful example for learning Mathematica programming.

In the function WalkD,I see the construct of While(it is common in procedural programming paradigm).I know Mathematica's functional programming paradigm is very elegent,so I'd like to use the function NestWhile to rewrite the the construct of While.

Origin program:

WalkD[f_, x_] := Module[{derivative, oldderivative, k}, 
    derivative = d[f, x]; displayStart[derivative];

   (*First While construct*)
    While[! FreeQ[derivative, d],
        oldderivative = derivative; k = 0;

        (*Second while construct*)
        While[oldderivative == derivative,
                  k++;
                  derivative = derivative /. 
                          ToExpression[StringReplace[$RuleNames[[k]], " " -> ""]]];
        displayDerivative[derivative, k]];
    D[f, x]]

My trial to rewrite the inner While construct

WalkDRewrite[f_, x_] :=
 Module[
  {derivative, oldderivative, k},
   derivative = d[f, x];
   displayStart[derivative];

 While[! FreeQ[derivative, d],
  oldderivative = derivative;
  k = 0;

 (*begin to rewrite*)
 NestWhile[
   CompoundExpression[#2++,
     #1 = #1 /. ToExpression[StringReplace[$RuleNames[[k]], " " -> ""]]] &,
   Sequence[derivative, k],
   oldderivative != derivative
 ]
 (*end *)

  displayDerivative[derivative, k]
 ];
 D[f, x]
]

However,I failed after debugging all morning.

Question:

Is it possible to use NestWhile to replace While?Thanks sincerely!

$\endgroup$
  • 1
    $\begingroup$ Try using {derivative,k} in place of Sequence[derivative,k] and either (1) use Apply with your CompoundExpression[...]&, i.e., CompoundExpression[...]&@@#&, or (2) change #1 and #2 to #[[1]] and #[[2]], respectively. $\endgroup$ – kglr Sep 4 '14 at 8:41
  • $\begingroup$ @kguler,thanks:),there is no warning information appeared with your suggestion.However,I feel this program is stuck in a vicious circle.Namely,it cannot achieve correct result. $\endgroup$ – xyz Sep 4 '14 at 8:57
  • $\begingroup$ related: Can every usage of While be changed into NestWhile? $\endgroup$ – Karsten 7. Sep 4 '14 at 9:16
3
$\begingroup$

Let's look at the inner loop:

While[oldderivative == derivative,
          k++;
          derivative = derivative /. 
                  ToExpression[StringReplace[$RuleNames[[k]], " " -> ""]]];

The first observation is that you have two variables which you change in the original While loop, derivative and k, but NestWhile supports only one function argument. But that is easily solved by passing a list containing those two variables.

The test function therefore is easy:

#[[1]] == oldderivative &

The actual evaluation function gives the new values as function of the old values. Note that #[[2]] is the old value of k, therefore an extra +1 is needed:

{ #[[1]] /. ToExpression[StringReplace[$RuleNames[[ #[[2]]+1 ]], " " -> ""]],
  #[[2]]+1 }&

And the initial values are, of course, derivative and 0.

Now we already see that the expressions get quite complicated, therefore we should make use of some function definitions, which also allows to make the code more readable through pattern matching. The inner loop body function makes a great candidate for this:

derivativeReplace[{derivative_, k_}] :=
   { derivative /. ToExpression[StringReplace[$RuleNames[[k+1]], " " -> ""]],
     k+1 }

Therefore the inner loop should look like this:

{derivative, k} =
  NestWhile[derivativeReplace, {derivative, 0}, #[[1]] == oldderivative &]

And thus the outer loop now is

While[! FreeQ[derivative, d],
    oldderivative = derivative;

    {derivative, k} =
      NestWhile[derivativeReplace, {derivative, 0},#[[1]] == oldderivative &]
    displayDerivative[derivative, k]];

Now the first thing you see is that derivative is no longer changed before NestList returns, therefore we can completely get rid of oldderivative:

While[! FreeQ[derivative, d],
    {derivative, k} =
      NestWhile[derivativeReplace, {derivative, 0}, #[[1]] == derivative &];
    displayDerivative[derivative, k]];

Note that k is only needed for displayDerivative, and not further used. To isolate the reassignment of derivative (which we need to do to replace the outer loop), we can use an anonymous helper function:

While[! FreeQ[derivative, d],
  derivative = Function[{deriv, k},
                        displayDerivative[deriv, k]; deriv] @@
      NestWhile[derivativeReplace, {derivative, 0}, #[[1]] == derivative &]];

Now the outer loop is in the perfect form for translation into NestWhile:

NestWhile[
  Function[derivative,
    Function[{deriv, k}, displayDerivative[deriv, k]; deriv] @@
      NestWhile[derivativeReplace, {derivative, 0}, #[[1]] == derivative &]],
        derivative, ! FreeQ[#, d]&];

Note that I ignore the return value of the outer NestWhile since derivative is no longer used after the rule. The complete function replacement therefore reads:

derivativeReplace[{derivative_, k_}] :=
   { derivative /. ToExpression[StringReplace[$RuleNames[[k+1]], " " -> ""]],
     k+1 }

WalkDReplacement[f_, x_] := Module[{derivative}, 
  derivative = d[f, x]; displayStart[derivative];

  NestWhile[
    Function[derivative,
      Function[{deriv, k}, displayDerivative[deriv, k]; deriv] @@
        NestWhile[derivativeReplace, {derivative, 0}, #[[1]] == derivative &]],
        derivative, ! FreeQ[#, d]&];

  D[f, x]]
$\endgroup$
  • $\begingroup$ ,Thanks! Dear celtschk, I have modified some mistakes in your answer and debug the program of the inner While construct. However, I cannot understand the outer While construct that you rewrite, namely,I cannot debug it. Lastly, by this question, I feel that it is hard to rewrite the While construct to NestWhile construct sometimes, as well as it is easy to understand Whileconstruct sometimes. $\endgroup$ – xyz Sep 5 '14 at 2:42
  • $\begingroup$ I've now fixed the error in my code; my tests indicate it works now correctly. The error was rather stupid: I forgot to supply the initial argument and test function to NestWhile, and to close the remaining open function argument brackets. $\endgroup$ – celtschk Sep 5 '14 at 17:07
  • $\begingroup$ @Tangshutao: Anyway, I forgot: thank you for correcting my other mistakes (and I also forgot the @-attribution so you get notified). $\endgroup$ – celtschk Sep 5 '14 at 17:17
  • $\begingroup$ I think this shows why I didn't try to use NestWhile[] in that routine. :) $\endgroup$ – J. M. will be back soon Aug 14 '16 at 9:32

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.