Рекурсивные функции в Mathematica

#wolfram-mathematica

#wolfram-mathematica

Вопрос:

В настоящее время я изучаю Mathematica и читал некоторые конспекты лекций, в которых пытались объяснить рекурсивные функции, затем они привели следующие примеры:

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

mapg[{}] := {};

mapg[{a, b, c}]
  

что дает результат: {g [a], g [b], g[c]}

Хотя я понимаю значение отдельных функций (Prepend, Rest, First), я не понимаю, как это рекурсивная функция и как она на самом деле работает, чтобы выдавать результат, который она дает.

Другой приведенный пример:

 
primefactorial[1] := 1;

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

primefactorial /@ Range[23]
  

Что дает результат: {1, 2, 6, 6, 30, 30, 210, 210, 210, 210, 2310, 2310, 30030, 30030,
30030, 30030, 510510, 510510, 9699690, 9699690, 9699690, 9699690,
223092870}

Опять же, хотя я понимаю, что делает функция PrimeQ и функция If, я не понимаю, что делает фактическая рекурсивная функция. В частности, что делает «n #» в функции If? Кроме того, что делает @primefactorial[n-1] ? Что именно применяется к primefactorial[n-1]?

Ответ №1:

Первый

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

mapg[{}] := {};

mapg[{a, b, c}]
  

это просто способ записи Map[g, list] с добавлением g[First[list]] mapg[Rest[list]] . Ключевой частью здесь является то, что они определили

 mapg[{}] = {}
  

так что есть конкретный базовый вариант, и вы не повторяете бесконечно. Это работает, потому что

 Rest[{a}] == {}
  

Если вы развернете то, что происходит поэтапно в этом вызове, вы получите

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

Второй случай немного сложнее, поскольку они использовали чистую (анонимную) нотацию функций. В этом случае они имеют

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

который просто говорит, что если n это простое число, то умножьте его на предыдущее разложение факториала, в противном случае ничего не делайте и просто верните предыдущее разложение.

Рекурсия происходит на primefactorial[n - 1] шаге, где снова для предотвращения бесконечной рекурсии они определили

 primefactorial[1] = 1
  

Вы могли бы символически расширить это следующим образом

 symbolicPrimeFactorial[1] := prime[1];
symbolicPrimeFactorial[n_] := If[PrimeQ[n], prime[n]*#, #] amp;@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]
  

и, надеюсь, это довольно ясно, что происходит

Комментарии:

1. Большое вам спасибо! У меня только что возник быстрый вопрос о первом примере, когда вы упомянули разворачивание, чтобы посмотреть, что происходит поэтапно, и написали: mapg[{a, b, c}] == Prepend[Prepend[Prepend[{}, c], b], a] Почему это не так, mapg[{a, b, c}] == Prepend[Prepend[Prepend[{}, g[c]], g[b]], g[a]] вместо этого? Или я неправильно понял ваше объяснение?

2. @user839136 это то, что я просто забыл о g переносе. Конечно, следует отметить, что на самом деле мы никогда не использовали бы просто такую функцию. Гораздо лучше использовать Map вместо