Страница 1 из 2

Рекурсивный вызов функции

Добавлено: 23 окт 2024, 16:36
Sertik
Как мы знаем, чтобы функция могла вызвать саму себя, нужно её объявить изнутри:

Код: Выделить всё

:global TestFunction do={
:if ($1="recursive") do={
:global TestFunction
[$TestFunction]
:put "recursive call"}
:put OK
}
Теперь если мы просто вызовем функцию [$TestFunction], то получим в Терминал "OK"
а если протестируем наш рекурсивный вызов [$TestFunction recursive], то получим "recursive call" и "OK"

Мне стало интересно, можно ли вызвать функцию рекурсивно не указывая её явного имени, ведь мы знаем, что функция - это всегда массив и её имя хранится в первом элементе этого массива $0. Только вот беда, хранится там оно ещё и с префиксом "$" (зачем - это к разработчикам Микротик)
Так вот, после танцев с бубнами (то есть танцев с :parse) и отсечения префикса $ с помощью :pick, оказалось, что можно:

Код: Выделить всё

:global  AnyName do={
:if ($1="test") do={
[[:parse [:parse ":global [:pick \$$0 1 [:len \$$0]]"]]];
[[:parse [:parse "[:pick \$$0 1 [:len \$$0]]"]]]
:put "Recursive call without mentioning the function name works"}
:put OK
}
Теперь если функцию кто-нибудь переименует, то в коде её объявление и рекурсивный вызов переименовывать не нужно ! всё и так сработает, так как используя мой код указывать явное имя при рекурсивном вызове не требуется (оно будет взято из $0 самой функции каким бы оно ни было).

Re: Рекурсивный вызов функции

Добавлено: 24 окт 2024, 09:56
Sertik
Но, как выяснилось это работает только без передачи аргументов в функцию, а при этом рекурсивный вызов теряет смысл. Надо ещё потестировать :-)

Re: Рекурсивный вызов функции

Добавлено: 24 окт 2024, 10:27
Sertik
Вот такой пример правильный:

Код: Выделить всё

:global CountDown do={
:if ($1>0) do={:put $1; :set $1 ($1-1);[[:parse "global $[:pick $0 1 [:len $0]]; [$0 $1]"]];}
:return "end"
}
:put [$CountDown 5]

5
4
3
2
1
end

Если требуется передавать большее количество аргументов или/и именованные аргументы их все надо указывать в :parse
В общем итоговая фраза для объявления и сразу последующего вызова рекурсивного вызова функции без указания её имени такая:

Код: Выделить всё

[[:parse "global $[:pick $0 1 [:len $0]]; [$0 $1 $2 $Par1 $Par2]"]]

Re: Рекурсивный вызов функции

Добавлено: 24 окт 2024, 13:32
Brook
А если использовать :execute, то не надо будет объявлять глобальную переменную и парсить имя. Параметры тоже работают.
Правда в таком случае - функция не вернет ничего, но иногда это и не надо. Зато рекурсивный вызов будет выполняться в отдельном процессе.

Например:

Код: Выделить всё

:global teGetTime
:if (!any $teGetTime) do={ :global teGetTime do={

	:local timeM [/system clock get time]
	:if ([:len $1] != 0) do={
		:log info "Param $1"
		:execute script="[$0]"
	} else={
		:log info "No param"
		:log info "$timeM"
	}
  }
}


Re: Рекурсивный вызов функции

Добавлено: 24 окт 2024, 14:39
Sertik
А в этом случае, чтобы был возврат из функции разве нельзя использовать:

Код: Выделить всё

	:return [:execute script="[$0]"]
?

Re: Рекурсивный вызов функции

Добавлено: 24 окт 2024, 15:01
Brook
Sertik писал(а): 24 окт 2024, 14:39 А в этом случае, чтобы был возврат из функции разве нельзя использовать:

Код: Выделить всё

	:return [:execute script="[$0]"]
?
Можно, но вернется .id задания на странице Job.

Re: Рекурсивный вызов функции

Добавлено: 24 окт 2024, 15:06
Sertik
Попробовал. У меня кстати

Код: Выделить всё

[:execute script="[$0 ftp]"]
не передает параметр "ftp" внутрь для функции $0. Как Вы передаете параметры ?

Re: Рекурсивный вызов функции

Добавлено: 24 окт 2024, 15:14
Brook
Sertik писал(а): 24 окт 2024, 15:06 Попробовал. У меня кстати

Код: Выделить всё

[:execute script="[$0 ftp]"]
не передает параметр "ftp" внутрь для функции $0. Как Вы передаете параметры ?
Так и передаю. У меня принимает.

Re: Рекурсивный вызов функции

Добавлено: 24 окт 2024, 15:23
Sertik
Да, но Вы делаете :global teGetTime явно. А у меня задача была объявлять функцию для рекурсии не упоминая явно её имя, а вытаскивая его из $0. Может в этом дело ?

Re: Рекурсивный вызов функции

Добавлено: 24 окт 2024, 15:38
Brook
Sertik писал(а): 24 окт 2024, 15:23 Да, но Вы делаете :global teGetTime явно. А у меня задача была объявлять функцию для рекурсии не упоминая явно её имя, а вытаскивая его из $0. Может в этом дело ?
Это просто хвосты остались. Убрал.

Тут тоже из $0 получаем имя функции. Сократил немного, чтоб понятней было.
И если в этом коде добавить параметр :execute script="[$0 ftp]", то получим вечный цикл.

Код: Выделить всё


:if (!any $teGetTime) do={ :global teGetTime do={

	:local timeM [/system clock get time]
	
	:if ([:len $1] != 0) do={
		:execute script="[$0]"
	} else={
		:log info "$timeM"
	}
  }
}