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

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

f=@(cn,n,f)eval('if n>1; f(cn*n,n-1,f);else;ans=cn;end');
f=@(n)f(1,n,f);

Или в качестве альтернативы:

f=@(cn,n,f)eval('if n>1; f(cn*n,n-1,f);else;disp(cn);end');
f=@(n)f(1,n,f);

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

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

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

1 ответ

Решение

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

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

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

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

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

fac = @(n,f)if_(n>1,{@()n*f(n-1,f),@()1})
factorial_=@(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);
factorial_=@(n)fac(n,fac);
factorial_(10)

РЕДАКТИРОВАТЬ: забавный факт: что мы делаем с линией

 factorial_=@(n)fac(n,fac);

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

 Y = @(f)@(x)f(x,f);
 factorial_=Y(f);
Другие вопросы по тегам