Рекурсивная анонимная функция Matlab

Я знаю, что это не то, для анонимных функций, но так же, как головоломка, я попытался сделать рекурсивную функцию через анонимные функции. Прообразом рекурсивных функций, очевидно, является факторная функция. Проблема состоит в том, что трудно выполнить различие в рамках анонимных функций. То, что мне удалось сделать до сих пор, следующее:

[email protected](cn,n,f)eval('if n>1; f(cn*n,n-1,f);else;ans=cn;end');
[email protected](n)f(1,n,f);

Или, альтернативно:

[email protected](cn,n,f)eval('if n>1; f(cn*n,n-1,f);else;disp(cn);end');
[email protected](n)f(1,n,f);

Что не очень удовлетворительно, так это то, что вы по-прежнему не можете использовать эту функцию при прямом назначении, a=f(3) все еще производит ошибку, так как eval не получает значения.

Итак, мой вопрос: можете ли вы на самом деле сделать рекурсивную функцию через анонимные функции, например, вычисляет факториал таким образом, который позволяет, например, a=f(3), полагаясь только на собственные функции matlab (или функции, которые вы можете создать в командной строке, как это было в моем примере)?

PS: Я знаю, что это не имеет практического применения, это просто вызов того, насколько вы можете сгибать и злоупотреблять синтаксисом Matlab.

Ответ 1

Теперь мы обнаружили две возможности: оба полагаются на использование массивов ячеек. Обратите внимание, что это может не работать в Octave.

Ключ был осуществлением разграничения случая. Первый, который я нашел, можно найти здесь.

Этот метод использует логические значения matlabs, значение true может быть оценено как 1, а false может быть оценено как 0.

if_ = @( pred_, cond_ ) cond_{ 2 - pred_ }();

Здесь мы должны предоставить условие в качестве первого аргумента и 2-элементный массив ячеек в качестве второго аргумента. Каждый элемент ячейки должен быть дескриптором функции, который вызывается, если условие истинно/не истинно. Наша факториальная функция будет выглядеть так:

fac = @(n,f)if_(n>1,{@()n*f(n-1,f),@()1})
[email protected](n)fac(n,fac);
factorial_(10)

Как @AndrasDeak прокомментировал ниже: Важная часть здесь заключается в том, что у нас есть массив ячеек функций, а не значений. Это обеспечивает короткое замыкание, поскольку n*f(n-1,f) не оценивается, если мы не вызываем соответствующую функцию @()n*f(n-1,f).

второй метод был обнаружен @beaker и несколько более гибким:

iif = @(varargin) varargin{2*find([varargin{1:2:end}], 1, 'first')}();

Это использует тот факт, что вы можете использовать varargin (переменное количество аргументов) даже в анонимных функциях. Когда вы вызываете эту функцию, вы должны чередовать условия и что должно выполняться, если условие истинно. Это даже позволяет построить конструкцию switch или конструкцию if ... else if ... else if ... (...) else .... Когда он вызывается, он будет искать первое условие, которое истинно (find([varargin{1:2:end}], 1, 'first')), и вызовет соответствующую функцию. Наш пример факториальной функции выглядит следующим образом:

fac = @(n,f)iif(n>1,@()n * f(n-1,f),true,@()1);
[email protected](n)fac(n,fac);
factorial_(10)

EDIT: Интересный факт: что мы делаем с линией

 [email protected](n)fac(n,fac);

также известен как применение Y-combinator. На самом деле мы можем записать, что как

 Y = @(f)@(x)f(x,f);
 factorial_=Y(f);