По мотивам - http://programmingmindstream.blogspot.ru/2015/12/1162.html?showComment=1450717154802#c256225446808977907
Предыдущая серия была тут - #1149. О кешировании. Поговорим про добавление вложенных элементов.
Ну и тут поступил вопрос про параметры слов (функций) - http://programmingmindstream.blogspot.ru/2015/12/1162.html?showComment=1450717154802#c256225446808977907.
Раз есть вопрос, то постараюсь описать - как определяются слова и их параметры.
Историю коммитов можно посмотреть тут - https://bitbucket.org/lulinalex/mindstream/commits/branch/B284_Inheritance_Try.
Ещё раз оговорюсь:
Идеологически наша скриптовая машина построена на стековой FORTH-машине - https://ru.wikipedia.org/wiki/%D0%A4%D0%BE%D1%80%D1%82_(%D1%8F%D0%B7%D1%8B%D0%BA_%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F)
.
Так что - было бы неплохо ознакомится с языком FORTH.
Для "общего понимания".
Итак.
Простейшее слово определяется так:
Пример можно скопировать в файл Example.script и запустить:
call.ms.script.exe Example.script или
call.ms.script.exe Example.script > a.out
Утилита call.ms.script.exe находится тут - https://bitbucket.org/lulinalex/mindstream/src/0bea4adaed7cbc645faa484fcb38f8aae6562827/Examples/Scripts/call.ms.script.exe?at=B284_Inheritance_Try
Замечение:
Утилита может молча не запускаться, это значит, что её блокирует антивирус. Так как она "получена не из благонадёжного источника".
В этом случае её стоит проверить антивирусом и включить в список разрешённых программ.
Продолжим.
Естественно, как и в любом другом языке программирования, у нас слова могут иметь параметры.
Простейший пример:
Можно расширить пример и определить ТИП параметра. Вот так:
Тогда в нашу функцию можно будет передать ТОЛЬКО ЦЕЛОЧИСЛЕННЫЕ значения.
Но о типах параметров и переменных мы поговорим чуть позже. В отдельной статье.
В качестве "лирического отступления" рекомендую ознакомиться с описанием "базовой аксиоматики" - https://bitbucket.org/lulinalex/mindstream/src/a071353dbd21d3afaf8f42b774cc890e0f5a74ce/Examples/ScriptedAxiomatics/kwMain.rc.script?at=B284_Inheritance_Try&fileviewer=file-view-default
До сих пор мы рассмотрели ОДИН параметр слева.
Рассмотрим теперь НЕСКОЛЬКО параметров слева.
Пример:
Хорошо. Мы поговорили про передачу параметров в слово.
А как получить значение из слова?
Разберём этот вопрос.
Простейший пример:
Методика "оставления значения на стеке" используется не только в "допотопном FORTH", но и во вполне себе "современном Ruby" - https://ru.wikipedia.org/wiki/Ruby.
Тут есть один недостаток (он же на самом деле - преимущество) - вызываемая функция может не положить на стек НИЧЕГО, может положить ОДНО значение, а может положить НЕСКОЛЬКО значений.
А вызывающая сторона этот факт не сможет проконтроллировать.
Как быть?
Для этого нам надо определить ТИП ВОЗВРАЩАЕМОГО значения.
Пример:
В данном случае, скриптовая машина ГАРАНТИРУЕТ, что будет возвращено ОДНО целочисленное значение. ОДНО и ТОЛЬКО ОДНО.
Но "есть одно но".
Возврат - скриптовая машина - контроллирует, а вот забор со стека - нет.
И можно написать так.
Это иногда полезно, но как быть когда хочется "полного контроля"?
Для этого есть "аналоги" слова : - FUNCTION и PROCEDURE.
Пример:
В данном случае скриптовая машина будет контроллировать как число входящих значений, так и исходящих.
Ну и пример использования слова PROCEDURE:
Слово PROCEDURE - ГАРАНТИРУЕТ, что наше слово не вернёт НИ ОДНОГО ЗНАЧЕНИЯ.
Подведём итоги.
В данной статье мы рассмотрели ключевые слова :, ;, IN, FUNCTION, PROCEDURE.
А также передачу параметров словам и возврат значений из них.
Также мы слегка коснулись типизации значений.
Кроме типа INTEGER бывают ещё - STRING, OBJECT, CLASS, INTERFACE, CHAR, ARRAY, FILE, BOOLEAN.
А также есть ещё ANY - которое означает "значение любого типа". И PRINTABLE - которое означает "любое значение пригодное для вывода на печать".
А также - VOID, который означеает "гарантированное отсутствие значения".
Также есть ещё типы ITERATABLE, ORDINAL и ATOMIC. О них мы также поговорим позже.
Пока лишь пример из аксиоматики:
В следующей статье мы рассмотрим "параметры справа". Зачем они нужны и как ими пользоваться.
Надеюсь, что данная статья была вам полезна.
Предыдущая серия была тут - #1149. О кешировании. Поговорим про добавление вложенных элементов.
Ну и тут поступил вопрос про параметры слов (функций) - http://programmingmindstream.blogspot.ru/2015/12/1162.html?showComment=1450717154802#c256225446808977907.
Раз есть вопрос, то постараюсь описать - как определяются слова и их параметры.
Историю коммитов можно посмотреть тут - https://bitbucket.org/lulinalex/mindstream/commits/branch/B284_Inheritance_Try.
Ещё раз оговорюсь:
Идеологически наша скриптовая машина построена на стековой FORTH-машине - https://ru.wikipedia.org/wiki/%D0%A4%D0%BE%D1%80%D1%82_(%D1%8F%D0%B7%D1%8B%D0%BA_%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F)
.
Так что - было бы неплохо ознакомится с языком FORTH.
Для "общего понимания".
Итак.
Простейшее слово определяется так:
: // - признак начала слова A // - имя слова 1 >>std::out // - код слова - печатает число 1 или 1 . // - также печатает число 1 ; // - признак конца слова A // - вызов слова A
Пример можно скопировать в файл Example.script и запустить:
call.ms.script.exe Example.script или
call.ms.script.exe Example.script > a.out
Утилита call.ms.script.exe находится тут - https://bitbucket.org/lulinalex/mindstream/src/0bea4adaed7cbc645faa484fcb38f8aae6562827/Examples/Scripts/call.ms.script.exe?at=B284_Inheritance_Try
Замечение:
Утилита может молча не запускаться, это значит, что её блокирует антивирус. Так как она "получена не из благонадёжного источника".
В этом случае её стоит проверить антивирусом и включить в список разрешённых программ.
Продолжим.
Естественно, как и в любом другом языке программирования, у нас слова могут иметь параметры.
Простейший пример:
: A IN aParam // - определяем параметр aParam, слева от нашего слова A aParam // - получаем значение параметра . // - печатаем значение параметра : // A 1 A // - вызов нашего слова A с передачей ему ЗНАЧЕНИЯ числа 1 как значения параметра
Можно расширить пример и определить ТИП параметра. Вот так:
: A INTEGER IN aParam // - определяем ЦЕЛОЧИСЛЕННЫЙ параметр aParam, слева от нашего слова A aParam // - получаем значение параметра . // - печатаем значение параметра : // A 1 A // - вызов нашего слова A с передачей ему ЗНАЧЕНИЯ числа 1 как значения параметра
Тогда в нашу функцию можно будет передать ТОЛЬКО ЦЕЛОЧИСЛЕННЫЕ значения.
Но о типах параметров и переменных мы поговорим чуть позже. В отдельной статье.
В качестве "лирического отступления" рекомендую ознакомиться с описанием "базовой аксиоматики" - https://bitbucket.org/lulinalex/mindstream/src/a071353dbd21d3afaf8f42b774cc890e0f5a74ce/Examples/ScriptedAxiomatics/kwMain.rc.script?at=B284_Inheritance_Try&fileviewer=file-view-default
До сих пор мы рассмотрели ОДИН параметр слева.
Рассмотрим теперь НЕСКОЛЬКО параметров слева.
Пример:
: A INTEGER IN aParam1 // - определяем первый параметр INTEGER IN aParam2 // - определяем второй параметр aParam1 // - получаем значение параметра aParam1 aParam2 // - получаем значение параметра aParam2 + // - получаем сумму двух значений . // - печатаем получившийя результат ; // A 1 2 A // - вызываем наше слово A для двух ЦЕЛОЧИСЛЕННЫХ значений - 1 и 2
Хорошо. Мы поговорили про передачу параметров в слово.
А как получить значение из слова?
Разберём этот вопрос.
Простейший пример:
: A INTEGER IN aParam1 // - определяем первый параметр INTEGER IN aParam2 // - определяем второй параметр aParam1 // - получаем значение параметра aParam1 aParam2 // - получаем значение параметра aParam2 + // - получаем сумму двух значений // - тут ничего не печатаем, а просто оставляем полученное значение на стеке ; // A 1 2 A // - вызываем наше слово A для двух ЦЕЛОЧИСЛЕННЫХ значений - 1 и 2 . // - печатаем значение со стека, фактически то, что нам вернула функция A
Методика "оставления значения на стеке" используется не только в "допотопном FORTH", но и во вполне себе "современном Ruby" - https://ru.wikipedia.org/wiki/Ruby.
Тут есть один недостаток (он же на самом деле - преимущество) - вызываемая функция может не положить на стек НИЧЕГО, может положить ОДНО значение, а может положить НЕСКОЛЬКО значений.
А вызывающая сторона этот факт не сможет проконтроллировать.
Как быть?
Для этого нам надо определить ТИП ВОЗВРАЩАЕМОГО значения.
Пример:
INTEGER // - определяем тип возвращаемого значения и "неявную переменную" Result : A INTEGER IN aParam1 // - определяем первый параметр INTEGER IN aParam2 // - определяем второй параметр aParam1 // - получаем значение параметра aParam1 aParam2 // - получаем значение параметра aParam2 + // - получаем сумму двух значений >>> Result // - снимаем значение со стека и кладём его в переменную Result. ; // A 1 2 A // - вызываем наше слово A для двух ЦЕЛОЧИСЛЕННЫХ значений - 1 и 2 . // - печатаем значение со стека, фактически то, что нам вернула функция A
В данном случае, скриптовая машина ГАРАНТИРУЕТ, что будет возвращено ОДНО целочисленное значение. ОДНО и ТОЛЬКО ОДНО.
Но "есть одно но".
Возврат - скриптовая машина - контроллирует, а вот забор со стека - нет.
И можно написать так.
INTEGER // - определяем тип возвращаемого значения и "неявную переменную" Result : A INTEGER IN aParam1 // - определяем первый параметр INTEGER IN aParam2 // - определяем второй параметр aParam1 // - получаем значение параметра aParam1 aParam2 // - получаем значение параметра aParam2 + // - получаем сумму двух значений aParam1 и aParam2 + // - получаем сумму предыдущего значения и того, что лежало на стеке >>> Result // - снимаем значение со стека и кладём его в переменную Result. ; // A 1 2 3 A // - вызываем наше слово A для ТРЁХ значений - 1, 2 и 3
Это иногда полезно, но как быть когда хочется "полного контроля"?
Для этого есть "аналоги" слова : - FUNCTION и PROCEDURE.
Пример:
INTEGER // - определяем тип возвращаемого значения и "неявную переменную" Result FUNCTION // - используем FUNCTION вместо : A INTEGER IN aParam1 // - определяем первый параметр INTEGER IN aParam2 // - определяем второй параметр aParam1 // - получаем значение параметра aParam1 aParam2 // - получаем значение параметра aParam2 + // - получаем сумму двух значений >>> Result // - снимаем значение со стека и кладём его в переменную Result. ; // A 1 2 A // - вызываем наше слово A для двух ЦЕЛОЧИСЛЕННЫХ значений - 1 и 2 . // - печатаем значение со стека, фактически то, что нам вернула функция A
В данном случае скриптовая машина будет контроллировать как число входящих значений, так и исходящих.
Ну и пример использования слова PROCEDURE:
PROCEDURE // - используем PROCEDURE вместо : A INTEGER IN aParam1 // - определяем первый параметр INTEGER IN aParam2 // - определяем второй параметр aParam1 // - получаем значение параметра aParam1 aParam2 // - получаем значение параметра aParam2 + // - получаем сумму двух значений . // - печатаем полученное значение ; // A 1 2 A // - вызываем наше слово A для двух ЦЕЛОЧИСЛЕННЫХ значений - 1 и 2
Слово PROCEDURE - ГАРАНТИРУЕТ, что наше слово не вернёт НИ ОДНОГО ЗНАЧЕНИЯ.
Подведём итоги.
В данной статье мы рассмотрели ключевые слова :, ;, IN, FUNCTION, PROCEDURE.
А также передачу параметров словам и возврат значений из них.
Также мы слегка коснулись типизации значений.
Кроме типа INTEGER бывают ещё - STRING, OBJECT, CLASS, INTERFACE, CHAR, ARRAY, FILE, BOOLEAN.
А также есть ещё ANY - которое означает "значение любого типа". И PRINTABLE - которое означает "любое значение пригодное для вывода на печать".
А также - VOID, который означеает "гарантированное отсутствие значения".
Также есть ещё типы ITERATABLE, ORDINAL и ATOMIC. О них мы также поговорим позже.
Пока лишь пример из аксиоматики:
INTEGER BOOLEAN TYPE ORDINAL STRING ORDINAL TYPE ATOMIC ATOMIC TYPE COMPARABLE FILE ARRAY TYPE ITERATABLE ITERATABLE ATOMIC CASTABLE INTERFACE TYPE ANY ANY TYPE VARIANT ARRAY TYPE ITERATOR FUNCTOR TYPE VAR_REF
В следующей статье мы рассмотрим "параметры справа". Зачем они нужны и как ими пользоваться.
Надеюсь, что данная статья была вам полезна.
Комментариев нет:
Отправить комментарий