Search code examples
wolfram-mathematica

Recursive functions on Mathematica


I'm currently learning Mathematica and was reading through some lecture notes which were trying to explain recursive functions, they then went on to give the following examples:


mapg[list_] := Prepend[  mapg[Rest[list]] , g[First[list]] ]; 

mapg[{}] := {};

mapg[{a, b, c}]

which gives the output: {g[a], g[b], g[c]}

While I understand the meaning of the individual functions (Prepend, Rest, First), I don't understand how this is a recursive function and how it actually works to give the output that it gives.

Another example given is:


primefactorial[1] := 1;

primefactorial[n_] := If[PrimeQ[n], n # , #] &@primefactorial[n - 1]

primefactorial /@ Range[23]

Which gives the output: {1, 2, 6, 6, 30, 30, 210, 210, 210, 210, 2310, 2310, 30030, 30030, 30030, 30030, 510510, 510510, 9699690, 9699690, 9699690, 9699690, 223092870}

Again, while I understand what the PrimeQ function does and the If function, I'm confused about what the actual recursive function is doing. In particular what does "n #" do in the If function? Also what does @primefactorial[n-1] do? What is being applied to primefactorial[n-1] exactly?


Solution

  • The first one

    mapg[list_] := Prepend[  mapg[Rest[list]] , g[First[list]] ]; 
    
    mapg[{}] := {};
    
    mapg[{a, b, c}]
    

    is just a way to write Map[g, list] by prepending g[First[list]] to mapg[Rest[list]]. The key part here is that they've defined

    mapg[{}] = {}
    

    so that there's a concrete base case & you don't recurse infinitely. This works because

    Rest[{a}] == {}
    

    If you unwrap what's happening step-wise in that call you get

    mapg[{a, b, c}] == Prepend[Prepend[Prepend[{}, c], b], a]
    

    The second case is a bit more subtle, since they've used pure (anonymous) function notation. In this case they have

    If[PrimeQ[n], n # , #] &@primefactorial[n - 1] == 
      If[PrimeQ[n], n*primefactorial[n - 1], primefactorial[n - 1]]
    

    which just says if n is a prime number, then multiply it by the previous factorial expansion, otherwise do nothing and just return the previous expansion.

    The recursion comes in the primefactorial[n - 1] step, where again to prevent infinite recursion they've defined

    primefactorial[1] = 1
    

    You could symbolically expand this like

    symbolicPrimeFactorial[1] := prime[1];
    symbolicPrimeFactorial[n_] := If[PrimeQ[n], prime[n]*#, #] &@symbolicPrimeFactorial[n - 1]
    
    symbolicPrimeFactorial /@ Range[1, 23, 2] // Column
    
    prime[1]
    prime[1] prime[2] prime[3]
    prime[1] prime[2] prime[3] prime[5]
    prime[1] prime[2] prime[3] prime[5] prime[7]
    prime[1] prime[2] prime[3] prime[5] prime[7]
    prime[1] prime[2] prime[3] prime[5] prime[7] prime[11]
    prime[1] prime[2] prime[3] prime[5] prime[7] prime[11] prime[13]
    prime[1] prime[2] prime[3] prime[5] prime[7] prime[11] prime[13]
    prime[1] prime[2] prime[3] prime[5] prime[7] prime[11] prime[13] prime[17]
    prime[1] prime[2] prime[3] prime[5] prime[7] prime[11] prime[13] prime[17] prime[19]
    prime[1] prime[2] prime[3] prime[5] prime[7] prime[11] prime[13] prime[17] prime[19]
    prime[1] prime[2] prime[3] prime[5] prime[7] prime[11] prime[13] prime[17] prime[19] prime[23]
    

    and hopefully this is pretty clear as to what's going on