deff вставленное определение (анонимной) функции на языке Scilab

## Синтаксис

                deff(funcHeadline, funcBody)
                deff(definition)
                deff("[r1, r2, ...] = myFunc(in1, in2, ...)", funcBody)
                deff "r = myFunc(x,y) r = x^2 - y"
                deff "r = myFunc(x,y) x^2 - y"
                deff("r = @(x,y) x^2 - y")      // в качестве элемента анонимного контейнера

                myFunc = deff(funcHeadline, funcBody)
                myFunc = deff(definition)
                myFunc = deff("[r1, r2, ...] = fakeName(in1, in2, ...)", funcBody)
                myFunc = deff("r = fakeName(x,y) r = x^2 - y")
                myFunc = deff("r = fakeName(x,y) x^2 - y")
                myFunc = deff("r = @(x,y) x^2 - y")

## Аргументы

x, y, in1, in2, ...
  входные аргументы определяемой функции. Последняя может иметь любое количество входных аргументов, от 0 до любого N.

r, r1, r2, ...
  результаты на выходе определяемой функции. Последняя может иметь любое количество результатов на выходе, от 0 до любого M. Все выходные аргументы должны быть явными, то есть, записанными слева от имени функции.

funcHeadline
  одиночная строка: заголовок функции, то есть, её первая строчка, указывающая локальное имя функции и списки её входных аргументов с правой стороны и выходных аргументов с левой стороны. Примеры:
  - `"myFunction(x,y)"` : нет аргументов на выходе
  - `"r = myFunction(x,y)"` : один аргумент на выходе
  - `"[a,b] = myFunction(x,y)"` : два аргумента на выходе. И т.д.
  Пожалуйста, обратите внимание, что a) ключевое слово `function` не обязательно указывать. b) запись выходных аргументов, если они есть, на левой части заголовочной строчки является обязательной.

funcBody
  вектор текстов, то есть Scilab-инструкций тела функции, в том порядке, в котором они должны быть выполнены. Эти инструкции должны определять и назначать значения всех выходных аргументов. Завершающее ключевое слово "endfunction" не ожидается.

  Этот вектор ожидается, когда `deff(…)` вызывается с двумя входными аргументами.

  Одинарные или двойные кавычки внутри инструкций должны дублироваться для защиты.

definition
  Отдельный текст или вектор текстов, включая как заголовочную строчку функции, так и тело.
  - Если это вектор, то это эквивалентно `definition = [funcHeadline ; funcBody]`.
  - В противном случае одностроковое определение эквивалентно `funcHeadline + " " + strcat(funcBody,"; ")`.
  Пожалуйста, смотрите разделы "Описание" и "Примеры".

myFunc
  Публичное имя и идентификатор определяемой функции, неявно возвращаемый в текущее окружение, либо явно присваиваемый переменной на выходе `deff(…)`.

  Когда `deff(…)` вызывается без явных выходных аргументов, но в качестве элемента контейнера или в качестве входного аргумента другой функции, то она неявно присваивается этому элементу или аргументу, который является анонимным. То тогда она является анонимной функцией. Например:

  `L = list(3, deff("r=noName(x) x.^2+1"), "Hello");`. Результат `deff(…)` присваивается `L(2)`. Тогда `L(2)(3.5) // ➜ 13.25`.

## Описание

`deff(…)` может использоваться для определения отдельной функции из инструкций Scilab, указанных через матрицу текстов, вместо любого внешнего текстового файла с инструкциями для исполнения, записанными в блок `function … endfunction`.

Файл исходного Scilab-кода может включать в себя определение нескольких публичных функций. Это не возможно сделать с помощью `deff(…)`: только одну публичную функцию можно определить. Однако, как и в случае с файлом, тело определяемой функции может включать в себя один или несколько блоков `function … endfunction`, определяющих вложенные приватные функции.

Независимо от синтаксиса `deff(…)`, используемого для обеспечения исходного кода (см. ниже), если он содержит синтаксическую ошибку, то `deff(…)` выдаст ошибку компиляции и остановит работу.

### Указание исходного кода

deff(funcHeadline, funcBody) (2 входа) и deff([funcHeadline ; funcBody]) (единый конкатенированный вход) эквивалентны.

Когда `funcBody` сделана только из одной (короткой) строки, она может быть приклеена и передана вместе с `funcHeadline`, как одностроковое определение функции. Примеры:

`deff("[a,b] = myFunction(x,y) a = x.^2; b = x-y;")`
`deff("r = myFunction(x,y) r = (x-y).^2")`. Это можно даже упростить до
`deff("r = myFunction(x,y) (x-y).^2")`
`deff("myFunction(x,y) disp(x.^2 - b)")`

Когда результат `deff(…)` присваивается или вводится в любой анонимный контейнер, то оказывается, что псевдоимя `fakeName`, определённое в `funcHeadline` не играет роли вообще, и может совсем не использоваться для вызова функции. Это имя может быть тогда заменено символом "@" в `funcHeadline` для указания, что определяемая функция становится анонимной.

### Идентификатор определяемой функции

Идентификатор - это фактическое слово (имя), которое используется для вызова определяемой функции. Следующие три случая представлены для примера.

Когда определяемая функция не предполагает присваиваемый результат, то её идентификатор возвращается напрямую в вызывающее окружение. Её публичное имя тогда является именем, используемым в заголовочной строчке представленного исходного кода.

В противном случае, когда `deff(…)` вызывается с явным выходным аргументом, то его имя становится единственным фактическим идентификатором публичной функции. В результате, имя функции, используемой в исходном коде, нельзя использовать для её вызова. Оно становится псевдоименем. По этой причине в заголовочной строчке может быть использован символ "@" (ставящийся для "анонимок") вместо какого-либо корректного имени функции, определённой в заголовочной строчке. Но это не обязательно.

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

## Примеры

### Неприсваивающие функции

                    deff('x = myplus(y,z)', 'x = y+z')
                    myplus(1,%i)

                    deff('[y, z] = mymacro(x)', ['y = 3*x+1'; 'z = a*x + x.^2'])
                    a = 3;
                    [u, v] = mymacro(2)

    --> deff('x = myplus(y,z)', 'x = y+z')
    --> myplus(1,%i)
     ans  =
       1. + i

    --> deff('[y, z] = mymacro(x)', ['y = 3*x+1'; 'z = a*x + x.^2'])
    --> a = 3;
    --> [u, v] = mymacro(2)
     v  =
       10.

     u  =
       7.

С единственным входным и выходным аргументом:

                    clear myFunc
                    source = ["r = myFunc(x,y)" ; "r = x.*(x-y)"]
                    deff(source)
                    myFunc(3, -2)

    --> source = ["r = myFunc(x,y)" ; "r = x.*(x-y)"]
     source  =
      "r = myFunc(x,y)"
      "r = x.*(x-y)"

    --> deff(source)
    --> myFunc(3, -2)
     ans  =
       15.

Тот же пример с одностроковым определением, которое затем позволяет синтаксис, ориентированный на командную строку (без необязательных скобок deff, но с, по-прежнему, обязательными разделительными кавычками):

                    clear myFunc
                    deff "r = myFunc(x,y) r = x.*(x-y)"
                    myFunc(1:3, -2)

    --> deff "r = myFunc(x,y) r = x.*(x-y)"
    --> myFunc(1:3, -2)
     ans  =
       3.   8.   15.

Для однострокового прямого определения с единственным выходным аргументом, мы можем даже опустить дубликат "r = " в теле функции:

                    clear myFunc
                    deff "r = myFunc(x,y) x.*(x-y)"
                    myFunc(1:3, -2)

    --> deff "r = myFunc(x,y) x.*(x-y)"
    --> myFunc(1:3, -2)
     ans  =
       3.   8.   15.

Функция без присваиваемого выходного аргумента: обратите также внимание на использование удвоенных кавычек для защиты их в строке определения:

                    clear myFunc
                    deff("myFunc(x, y) messagebox(prettyprint(x.*(x-y), ""html"",""""))")
                    myFunc([1 2 ; 3 4], -2)

### Определяемая функция, присваиваемая реципиенту

Придержимся примеров, похожих на приведённые выше:

                    clear myFunc actualName
                    actualName = deff("r = myFunc(x,y) x.*(x-y)")
                    isdef(["myFunc" "actualName"])
                    actualName(1:3, -2)
                    myFunc(1:3, -2)

    --> actualName = deff("r = myFunc(x,y) x.*(x-y)")
     actualName  =
    [r]=actualName(x,y)

    --> isdef(["myFunc" "actualName"])
     ans  =
      F T

    --> actualName(1:3, -2)
     ans  =
       3.   8.   15.

    --> myFunc(1:3, -2)
    Undefined variable: myFunc

Поскольку имя "внутренней" функции является псевдоименем, то мы можем вместо него использовать "@" (символ "@" нельзя использовать в фактических именах функций):

                    clear actualName
                    actualName = deff("r = @(x,y) x.*(x-y)");
                    actualName(1:3, -2)

    --> actualName = deff("r = @(x,y) x.*(x-y)");
    --> actualName(1:3, -2)
     ans  =
       3.   8.   15.

Теперь напрямую присвоим созданную функцию безымянному реципиенту. Хотя функция становится анонимной, мы, по-прежнему, можем вызывать её:

                    L = list("abc", deff("r = @(x,y) x.*(x-y)"), %z);
                    L(2)(1.1:4, -2.1)
                    // Мы можем извлекать и устанавливать имя анонимной функции:
                    Abc = L(2)
                    Abc(1.1:4, -2.1)

    --> L = list("abc", deff("r = @(x,y) x.*(x-y)"), %z);
    --> L(2)(1.1:4, -2.1)
     ans  =
       3.52   8.82   16.12

    --> Abc = L(2)
     Abc  =
    [r]=Abc(x,y)

    --> Abc(1.1:4, -2.1)
     ans  =
       3.52   8.82   16.12

Наконец, давайте используем `deff()` для прямого определения и передачи функции в качестве входного элемента другой функции:

                    function r = test(txt, x, theFunc)
                        r = x + theFunc(txt)
                    endfunction

                    test(rand(2,3), 0.7, deff("r = @(M) sum(size(M).^2)"))

    --> test(rand(2,3), 0.7, deff("r = @(M) sum(size(M).^2)"))
     ans  =
       13.7

В этом примере передаваемая функция является анонимной в вызывающем окружении, но присваивается и получает своё имя "theFunct" внутри вызываемой функции.

## Смотрите также

- function
- exec
- getd
- genlib
- jdeff
- jcompile

## История

6.0.0

- Входная опция `opt="c"|"p"|"n"` больше не доступна.
- Определяемая `newfunction` теперь имеет тип 13 (вместо 11).

6.1.1

- Добавлен необязательный выходной аргумент. Могут определяться анонимные функции.
- Поддерживаются одиночные входные аргументы, конкатенирующие заголовочную строку функции и её тело.
- Поддерживается синтаксис одиночной строки, вроде `deff "r = myFun(x,y) x.^2-y"`
- Поддерживается псевдоимя функции "@".