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

Здесь выкладываем скрипты
Правила форума
Уважаемые Пользователи форума, обратите внимание!
Ни при каких обстоятельствах, Администрация форума, не несёт ответственности за какой-либо, прямой или косвенный, ущерб причиненный в результате использования материалов, взятых на этом Сайте или на любом другом сайте, на который имеется гиперссылка с данного Сайта. Возникновение неисправностей, потерю программ или данных в Ваших устройствах, даже если Администрация будет явно поставлена в известность о возможности такого ущерба.
Просим Вас быть предельно осторожными и внимательными, в использовании материалов раздела. Учитывать не только Ваши пожелания, но и границы возможностей вашего оборудования.
Sertik
Сообщения: 1658
Зарегистрирован: 15 сен 2017, 09:03

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

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

: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 самой функции каким бы оно ни было).


фрагменты скриптов, готовые работы, статьи, полезные приемы, ссылки
viewtopic.php?f=14&t=13947
Sertik
Сообщения: 1658
Зарегистрирован: 15 сен 2017, 09:03

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


фрагменты скриптов, готовые работы, статьи, полезные приемы, ссылки
viewtopic.php?f=14&t=13947
Sertik
Сообщения: 1658
Зарегистрирован: 15 сен 2017, 09:03

Вот такой пример правильный:

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

: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]"]]


фрагменты скриптов, готовые работы, статьи, полезные приемы, ссылки
viewtopic.php?f=14&t=13947
Аватара пользователя
Brook
Сообщения: 156
Зарегистрирован: 24 май 2022, 00:29

А если использовать :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"
	}
  }
}



Sertik
Сообщения: 1658
Зарегистрирован: 15 сен 2017, 09:03

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

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

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


фрагменты скриптов, готовые работы, статьи, полезные приемы, ссылки
viewtopic.php?f=14&t=13947
Аватара пользователя
Brook
Сообщения: 156
Зарегистрирован: 24 май 2022, 00:29

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

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

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


Sertik
Сообщения: 1658
Зарегистрирован: 15 сен 2017, 09:03

Попробовал. У меня кстати

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

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


фрагменты скриптов, готовые работы, статьи, полезные приемы, ссылки
viewtopic.php?f=14&t=13947
Аватара пользователя
Brook
Сообщения: 156
Зарегистрирован: 24 май 2022, 00:29

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

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

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


Sertik
Сообщения: 1658
Зарегистрирован: 15 сен 2017, 09:03

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


фрагменты скриптов, готовые работы, статьи, полезные приемы, ссылки
viewtopic.php?f=14&t=13947
Аватара пользователя
Brook
Сообщения: 156
Зарегистрирован: 24 май 2022, 00:29

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"
	}
  }
}



Ответить