Научная статья на тему 'РАЗРАБОТКА И АНАЛИЗ ПОСТЕПЕННОГО ВНЕДРЕНИЯ ПРОВЕРКИ И ВЫВОДА ТИПОВ ДАННЫХ С ИСПОЛЬЗОВАНИЕМ ЯЗЫКА ПРОГРАММИРОВАНИЯ TYPESCRIPT И ЛЯМБДА-ИСЧИСЛЕНИЯ'

РАЗРАБОТКА И АНАЛИЗ ПОСТЕПЕННОГО ВНЕДРЕНИЯ ПРОВЕРКИ И ВЫВОДА ТИПОВ ДАННЫХ С ИСПОЛЬЗОВАНИЕМ ЯЗЫКА ПРОГРАММИРОВАНИЯ TYPESCRIPT И ЛЯМБДА-ИСЧИСЛЕНИЯ Текст научной статьи по специальности «Компьютерные и информационные науки»

CC BY
79
21
i Надоели баннеры? Вы всегда можете отключить рекламу.
Ключевые слова
typescript / javascript / types / lambda calculus / compiler. / typescript / javascript / types / lambda calculus / compiler.

Аннотация научной статьи по компьютерным и информационным наукам, автор научной работы — Князев И.В., Коптева А.В.

В статье анализируется проверка и вывод типов данных, разрабатывается компилятор с использованием языка программирования TypeScript, описывается и применяется типизированное лямбда-исчисление для написания выражений и функций.

i Надоели баннеры? Вы всегда можете отключить рекламу.
iНе можете найти то, что вам нужно? Попробуйте сервис подбора литературы.
i Надоели баннеры? Вы всегда можете отключить рекламу.

ANALYZE THE GRADUAL IMPLEMENTATION OF DATA TYPE VALIDATION AND INFERENCE USING THE TYPESCRIPT PROGRAMMING LANGUAGE AND LAMBDA CALCULUS

The article analyzes data type checking and inference, develops a compiler using the TypeScript programming language, describes and applies typed lambda calculus to write expressions and functions.

Текст научной работы на тему «РАЗРАБОТКА И АНАЛИЗ ПОСТЕПЕННОГО ВНЕДРЕНИЯ ПРОВЕРКИ И ВЫВОДА ТИПОВ ДАННЫХ С ИСПОЛЬЗОВАНИЕМ ЯЗЫКА ПРОГРАММИРОВАНИЯ TYPESCRIPT И ЛЯМБДА-ИСЧИСЛЕНИЯ»

Юбернетика та системний анал1з. 2016. № 1(46). С. 99-102.

13. Дадик В. О., Кириленко В. А. Закордон-ний досвщ використання шформацшно-аналггич-них систем управлшня дгями частин i шдроздшв. Труди утверситету: s6ipHUK наукових праць. 2020. №3(159). С. 148-157, шв.№49015т.

14. Склад i структура автоматизованих систем URL: http://um.co.ua/5/5-1/5-1504.html (дата звернення: 22.08.2021).

15. Проектування автоматизованих систем URL: http://um.co.ua/10/10-7/10-73799.html (дата звернення: 22.08.2021).

16. Лекщя 13. Наукова методолопя. Ф1зика як основа природознавства URL: http://ni.biz.ua/3/3_3/3_3246_lektsiya--nauchnaya-metodologiya-fizika-kak-osnova-estestvoznaniya.html (дата звернення: 12.08.2021).

17. Колачов С. П., ШелепенкоЮ. В., Зеленко О. В. Методика тдвищення якосп роботи оператора АСУ бойовими засобами за рахунок адапта-щйно1 змши штенсивносп входного потоку заявок на обслуговування. 36ipnuK наукових праць Втськового iHcmumymy телекомумкацп та iнформатизацiï. 2006. № 2. С. 32-36.

РАЗРАБОТКА И АНАЛИЗ ПОСТЕПЕННОГО ВНЕДРЕНИЯ ПРОВЕРКИ И ВЫВОДА ТИПОВ ДАННЫХ С ИСПОЛЬЗОВАНИЕМ ЯЗЫКА ПРОГРАММИРОВАНИЯ TYPESCRIPT И

ЛЯМБДА-ИСЧИСЛЕНИЯ

Князев И.В.

Старший разработчик программного обеспечения в June Homes

Белгород, Россия Коптева А.В.

Старший разработчик программного обеспечения в Яндекс

Москва, Россия

ANALYZE THE GRADUAL IMPLEMENTATION OF DATA TYPE VALIDATION AND INFERENCE USING THE TYPESCRIPT PROGRAMMING LANGUAGE AND LAMBDA CALCULUS

Kniazev I.

Senior Software Developer at June Homes Belgorod, Russia Kopteva A.

Senior Software Developer at Yandex Moscow, Russia

АННОТАЦИЯ

В статье анализируется проверка и вывод типов данных, разрабатывается компилятор с использованием языка программирования TypeScript, описывается и применяется типизированное лямбда-исчисление для написания выражений и функций.

ABSTRACT

The article analyzes data type checking and inference, develops a compiler using the TypeScript programming language, describes and applies typed lambda calculus to write expressions and functions.

Ключевые слова: typescript, javascript, types, lambda calculus, compiler.

Keywords: typescript, javascript, types, lambda calculus, compiler.

Синтаксис

Единственная синтаксическая категория в лямбда-исчислении - это выражения. Выражение -

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

1 EXPRESSION = INT

2 1 VAR

3 1 FUNCTION

А 1 CALL

5 1 IF

6 7 1 '(' EXPRESSION ')'

/ 8 INT = 0 | 1 |

9 VAR = NAME

10 FUNCTION = 1( 1 NAME ')' => EXPRESSION

11 CALL = EXPRESSION '(' EXPRESSION ')'

12 IF = 'if' ■ ■ EXPRESSION ')' EXPRESSION 'else' EXPRESSION

13

1А NAME = [a-zA- Z_][a-zA-Z0-9_]*

15 // a string of letters, numbers and underscore starting with a letter or underscore

Рис. 1. Описание синтаксиса лямбда-исчисления.

Анализируя код выше можно сделать вывод, что он является выражением, имея следующие признаки:

• Целочисленный литерал (например, 0, 1,...)

• Переменная (например, x, y, abc и т. д.)

• Функция (например, (x) => increment (x)); То же, что и в javascript, но только с одним аргументом.

• Вызов (например, f (1)) также только с одним аргументом

• If выражение (например, if (isEven (x)) 1 else 2)

Здесь следует отметить несколько моментов. Во-первых, все функции принимают 1 аргумент и возвращают 1 значение. Для функций с несколькими аргументами мы используем технику под названием «каррирование», например:

(x) => ((y) => (добавить (x)) (y))

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

(x) => (y) => добавить (x) (y)

Если данная функция вызывается с 1 аргументом (x), она вернет другую функцию, которая принимает 1 аргумент (y), которая вызывает add с параметром Х и снова вызывает результат этого с параметром Y.

Во-вторых, «If» в большинстве языков является выражением, а не утверждением. Это означает, что он «возвращает» значение при оценке, поэтому можно написать следующее:

(условие) => if (условие) 1 else 2

При вызове с истиной (true) эта функция вернет 1, в противном случае - 2.

Синтаксическое дерево

По сути, любая допустимая программа, которую пользователь вводит в файл, представлена как «Дерево» из «Узлов». Дерево - это структура, в которой есть узлы, содержащие информацию, и при необходимости могут быть дочерние узлы. Парсер берет исходный текст и преобразует его в древовидную структуру, которой компилятор может легко манипулировать. Это можно реализовать с помощью кода следующим образом:

1 type Expression = EInt | EVar | EFunc | ECall | Elf;

2 type EInt =

3 { nodeType: "Int", value: number >

4 type EVar =

5 { nodeType: "Var", name: string >

6 type EFunc =

7 { nodeType: "Function", param: string, body: Expression >

8 type ECall =

9 { nodeType: "Call", func: Expression, arg: Expression >

10 type Elf = {

11 nodeType: " If",

12 cond: Expression,

13 trueBranch: Expression,

14 falseBranch : Expression

15 >;

Рис. 2. Код синтаксического дерева.

Тип, представляющий дерево выражений можно написать следующим образом:

1 type Expression = EInt | EVar | EFunc | ECall | Elf;

2 type EInt =

3 { nodeType: "Int", value: number >

4 type EVar =

5 { nodeType: "Var", name: string >

6 type EFunc =

7 { nodeType: "Function", param: string, body: Expression >

8 type ECall =

9 { nodeType: "Call", func: Expression, arg: Expression >

10 type Elf = {

11 nodeType: " If",

12 cond: Expression,

13 trueBranch: Expression,

14 falseBranch : Expression

15 >;

Рис. 3. Код дерева выражений.

Анализируя код видно, что каждый узел выражения имеет свойство «nodeType», которое указывает, какой тип выражения является этим узлом, и некоторые значения, связанные с соответствующим типом.Оператор «|» означает, что тип Expression может иметь одну из этих структур. Вы-

ражение с типом «Ш» имеет свойство значения, содержащее число, которое оно представляет. Узел типа «Var"» содержит имя переменной.

Исходя из описанного выше можно составить выражение и объект дерева:

1 // (х) => if (х) 2 else f(x)

2 const node = {

3 nodeType: "Function",

4 param: "x",

5 body: {

6 nodeType: "If",

7 cond: {

8 nodeType: "Var",

iНе можете найти то, что вам нужно? Попробуйте сервис подбора литературы.

9 name: "x"

10

11 trueBranch:

12 nodeType: "Int",

13 value: 2

14

15 falseBranch:

16 nodeType: "Call",

17 func: "f",

18 arg: {

19 nodeType : "Var",

20 name: "x

21 >

22 }

23 }

24 >

Рис. 4. Код выражения и объекта дерева.

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

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

Поскольку в нашем исходном языке (пока) нет аннотаций типов, средство проверки типов, которое мы пишем, должно определять тип каждого выражения (и его подвыражений рекурсивно). Типы могут быть простыми типами (например, Int, Bool и т. д.), или типами функций (например, (Int) => Int - это функция, которая принимает Int и возвращает Int). Поскольку типы функций содержат другие типы, тип дерева является рекурсивным.

1 type Type = TNamed | TVar | TFun;

2 type TNamed = { nodeType: "Named", name: string }

3 type TVar = { nodeType: "Var", name: string >

4 type TFun = { nodeType: "Function", from: Type, to: Type >;

Рис. 5. Код описания типов.

«Named» (именованные) типы - это типы, которые были объявлены. Они включают в себя встроенные типы, такие как Int и Bool, и в будущем они также будут использоваться для представления объявленных пользователем типов, таких как типы записей.

Типы «Var» - это типовые переменные. Они могут заменить любой тип. Они могут быть «ин-станцированы» при использовании. Их используют для представления типов, которые еще не были выведены.

Тип «Функция» - это тип функции, которая принимает значение типа «от» и возвращает значение типа «до».

Typechecker (проверщик типов) Далее мы реализуем вывод типов и проверку с помощью метода под названием Hindley-Milner (HM). Большинство современных статически типизированных функциональных языков (Haskell, ML, F #) используют некоторые его вариации.

Обратите внимание, что основной целью HM было реализовать вывод типов для полиморфизма. В данном исследовании мы проигнорируем часть

полиморфизма и сосредоточимся на остальной части алгоритма.

Наша программа проверки типов поддерживает «среду», которая представляет собой просто отображение имен переменных и их предполагаемого типа. Мы начинаем с пустой среды и начинаем рекурсивно обходить дерево выражений сверху вниз. Когда мы определяем типы переменных, мы добавляем их в среду.

1 function inferte: Expression): Type { switch (e.nodeType) { case "Int": return { nodeType: "Named1

default: throw "Unimplemented"; >

В основе нашей проверки типов лежит функция под названием «unify». Он берет два типа и пытается их сопоставить. Если типы не совпадают, возвращается ошибка типа. Таким образом, функция вывода, использующая унификацию, сопоставляет типы дерева выражений и обеспечивает их соответствие.

name: "Int" };

>

Рис. 6. Код функции вывода типа.

Из кода видно, что когда он вызывается с выражением nodeType «Ш», на выходе получаем именованный тип «Ш».

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

ошибку, говоря, что переменная не входит в область видимости.

Итак, необходимо изменить функцию infer, чтобы она принимала дополнительный аргумент, который является средой переменных в области видимости:

1 // This is simply a map of variable names in scope to their types

2 type Env = {

3 [name: string]: Type;

4

5 function infer(env: Env, e: Expression): Type {

6 switch (e.nodeType) {

7 case "Int": return { nodeType: "Named", name: "Int" };

8 case "Var":

9 if (env[e.name]) {

10 return env[e.name];

11 > else {

12 throw 'Unbound var Sie-name}';

13 >

14 default: throw "Unimplemented";

15

16 >

Рис. 7. Код измененной функции infer.

Мы только что добавили регистр для nodeType «Var"». Это должно быть довольно просто.

Функции

Имея функцию нам необходимо определить тип ее тела - сделать рекурсивный вызов для вывода тела функции. Также тело может относиться к параметру функции, поэтому его нужно добавить в среду выполнения, сделав копию с одним дополнительным членом, который является параметром. Затем необходимо добавить <param_name, new_type_variable> в среду и передать новое окружение и тело функции в функцию вывода.

Теперь, во время вызова для вывода тела функции, мы можем найти фактический тип переменной типа, сгенерированной параметром. В общем, функция infer может найти фактические типы, которые обозначают эти переменные типа в среде:

(х) => not (х)

Если мы знаем, что not имеет тип Bool -> Bool, тогда x должен иметь тип Bool.

Таким образом, функция infer должна возвращать дополнительный результат вместе с типом

выражения. Он также должен возвращать отображение переменных типа в типы. Это отображение называется подстановкой. Подстановка сопоставляет переменные типа с типами, тогда как среда сопоставляет переменные (которые являются выражениями) с типами.

После того, как мы вызвали infer для тела, мы вернем тип (который является типом тела) и подстановку, которая может содержать или не содержать фактический тип переменной типа нашего параметра, которую мы добавили в среду. Таким образом, тип функции должен быть:

<type_of_param> -> <type_of_body>

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

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

Нам нужно «применить» возвращенную подстановку к сгенерированной нами переменной

1 type Context = {

2 next: number; // next type variable to be generated

3 env: Env; // mapping of variables in scope to types

4 >

5

6 //a map of type variable names to types assigned to them

7 type Substitution = {

8 [key: string]: Type;

9 }; 10

11 // replace the type variables in a type that are

12 // present in the given substitution and return the

13 // type with those variables with their substituted values

14 // eg. Applying the substitution {"a": Bool, "b": Int>

15 // to a type (a -> b) will give type {Bool -> Int)

16 function applySubstToType(subst: Substitution, type: Type): Type {

17 switch (type.nodeType) {

18 case "Named": return type;

19 case "Var":

20 if (substftype.name]) {

21 return subst[type.name];

22 > else {

23 return type;

24 >

25 case "Function":

26 return {

27 nodeType: "Function",

from: applySubstToTypefsubst, type.from),

29 to: applySubstToType(subst, type.to)

iНе можете найти то, что вам нужно? Попробуйте сервис подбора литературы.

30 >;

31 }

32 >

33

34 /**

35 * Add a new binding to the context's environment

36 */

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60 61 62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

function addToContext(ctx: Context, name: string, type: Type): Context { const newEnv = Object.assign){}, ctx, { env: Object.assignK}, ctx.env)

>>;

newEnv.envtname] = type; return newEnv;

function newTVar(ctx: Context): Type { const newVarNum = ctx.next; ctx.next++; return {

nodeType: "Var", name: 'T${newVarNum>'

>;

}

function infer(ctx: Context, e: Expression): [Type, Substitution] { const env = ctx.env; switch (e.nodeType) {

case "Int": return [{ nodeType: "Named", name: "Int" >, {}]; case "Var":

if (envfe.name]) {

return [env[e .name], {}]

> else {

throw 'Unbound var ${e.name}';

>

case "Function": {

const newType = newTVar(ctx);

const newCtx = addToContext(ctx, e.param, newType); const [bodyType, subst] = infer(newCtx, e.body); const inferredType: Type = { nodeType: "Function",

from: applySubstToTypetsubst, newType), to: bodyType

};

return [inferredType, subst];

>

default: throw "Unimplemented";

>

Рис. 8. Пример кода с применением подстановки

Обратите внимание, что параметр е^ заменился параметром контекста. Контекст содержит среду и некоторую другую информацию, которая может понадобиться.

Мы добавили новую функцию applySubstToType, которая рекурсивно проходит по узлу типа, а для переменных типа ищет их в данной подстановке и возвращает ее.

Функция addToContext принимает контекст, имя переменной и тип и добавляет отображение имени и типа в среду контекста. Обратите внимание, что он не изменяет исходный контекст или окружающую его среду. Он делает копию и возвращает новый контекст. Это связано с тем, что когда привязывается новая переменная, она должна быть

видимой только в той области видимости, в которой она была объявлена.

Функция newTVar принимает контекст, увеличивает его следующее свойство и возвращает переменную нового типа с именем T <context.next> (T1, T2,...). Каждый вызов будет генерировать новую переменную типа. Это действительно изменяет данный контекст, потому что сгенерированные имена должны быть уникальными для разных областей. Хотя это не является строго обязательным требованием, это немного упрощает реализацию.

Наконец, мы изменяем сигнатуру функции infer, чтобы она принимала контекст вместо среды, и теперь она возвращает тип и замену.

Вызов функций

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

Теперь необходимо применить полученную подстановку к контексту среды, чтобы тип любых переменных типа, выведенных в результате последнего вызова, был доступен для вызова для определения типа аргумента. Затем вызывается infer с этим новым контекстом и узлом аргумента.

Далее необходимо сопоставить тип аргумента с типом, ожидаемым функцией. Это не так просто, как просто сравнить типы. Типы могут содержать переменные типа, которые могут обозначать другие типы. Здесь и вступает в силу объединение.

По сути, унификация - это способ проверить, подходят ли 2 типа, и если они подходят, вернуть замену, которая уравнивает их. Например, попытаться объединить (Int -> A) и (Int -> Bool), то получим замену {«A»: Bool}, потому что «A» - это переменная типа, которая может заменять любой тип, а второй тип требует, чтобы он был Bool:

1

2

3

4

5

6

7

8 9

10 11 12

13

14

15

16

17

18

19

20 21 22

23

24

iНе можете найти то, что вам нужно? Попробуйте сервис подбора литературы.

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

function unifyltl: Type, t2: Type): Substitution { if (tl.nodeType == "Named"

&& t2.nodeType === "Named" 8.8. t2.name === tl.name) { return {>;

> else if (tl.nodeType === "Var") {

return varBind(tl.name, t2); } else if (t2.nodeType === "Var") {

return varBind(t2.name, tl); } else if (tl.nodeType === "Function" 8.8. t2.nodeType === "Function") { const si = unifyitl.from, t2.from); const s2 = unify(

applySubstToType(sl, tl.to), applySubstToType(sl, t2.to)

) ;

return composeSubsttsl, s2);

> else {

throw 'Type mismatch:\n Expected ${typeToString(tl)}\n Found ${typeToSt:

>

function composeSubst(si: Substitution, s2: Substitution): Substitution { const result: Substitution = {}; for (const k in s2) { const type = s2[k];

resultCk] = applySubstToTypelsl, type);

};

return { ...si, ...result };

>

function varBindlname: string, t: Type): Substitution { if (t.nodeType ==- "Var" 8.8. t.name === name) {

return {>; } else if (containsit, name)) {

throw 'Type S{typeToString(t)> contains a reference to itself";

> else {

const subst: Substitution = {}; subst[name] = t; return subst;

>

function containsit: Type, name: string): boolean { switch (t.nodeType) { case "Named": return false; case "Var": return t.name === name;

case "Function": return containsit.from, name) || contains(t.to, name);

>

>

Рис 9. Пример кода унификации

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

Если одна из них является переменной типа, а они одинаковы, необходимо возвращать нулевую замену.

Если одна из них является переменной типа, а другой тип содержит переменную того же типа, необходимо выдавать ошибку. Это потому, что их объединение привело бы к бесконечно рекурсивному типу. Например, если A и A -> B объединяются, это будет означать, что A - это A -> B, что будет означать, что A -> B это (A -> B) -> B.

Когда оба типа являются функциями, необходимо рекурсивно унифицировать их типы параметров и возвращаемые типы и составлять результирующие замены (используя composeSubst).

Также стоит обратить внимание, что и здесь, на каждом шаге, когда получаем новую замену, мы применяем ее к старым типам как способ обновить их новыми ограничениями, созданными путем вызова unify.

Вернемся к функции вывода для выражений вызова. Здесь генерируется новая переменная типа

для возвращаемого типа функции, затем выводим типы для аргументов функции, затем объединяется выведенный тип функции с типом <argType> -> <newVar>. Наконец, унифицируется тип параметра функции с фактическим типом аргумента, потому что нет необходимости иметь возможность передавать, скажем, Int в функцию, которая принимает аргумент Bool. На каждом этапе необходимо применять новые сгенерированные замены к более ранним типам.

Кроме того, необходимо использовать composeSubst, чтобы «составить» несколько замен. Функция composeSubst применяет первую замену к типам второй, а затем объединяет результат с первой заменой.

Выражения «If»

Здесь необходимо проверять, должен ли тип выражения условия унифицироваться с Bool, и типы обеих ветвей должны быть унифицированы. Затем необходимо возвращать тип первой ветки (возможно, это была и вторая ветвь, потому что обе объединяются):

1 function infertctx: Context, e: Expression): [Type, Substitution] {

2 const env = ctx.env;

3 switch (e. .nodeType) {

4 II ...

5 case "If":

6 const [condType, s0] = infer(ctx, e.cond);

7 const si = unify(condType, {

8 nodeType: "Named",

9 name: "Bool"

10 >);

11 const ctxl = applySubstToCtx(composeSubst(s0, si), ctx);

12 const [_trueBranchType, s2] = infer(ctxl, e.trueBranch) ;

13 const s3 = composeSubst(si, s2);

14 const ctx2 = applySubstToCtx(s2, ctxl);

15 const [_falseBranchType, s4] = infer(ctx2, e.falseBranch);

16 const s5 = composeSubst(s3, s4);

17

18 const trueBranchType = applySubstToTypets5, _trueBranchType);

19 const falseBranchType = applySubstToType(s5, _falseBranchType);

20 const s6 = unify(trueBranchType, falseBranchType);

21 const resultSubst = composeSubst(s5, s6);

22 return [

23 applySubstToType(s6, trueBranchType),

24 resultSubst

25 ] ;

26

27 }

28 III ...

29 >

30 >

Рис. 10. Код уницикации с помощью выражения «If»

Заключение

Таким образом, в данной статье разработан собственный компилятор на основе языка программирования Typescript и проанализирована работа вывода типов. Для тестирования typechecker необходимо вызвать функцию infer для деревьев выражений, чтобы проверить, соответствуют ли они типам и передав начальный контекст.

Литература

1. Документация TypeScript / Declaration Reference / [Электронный ресурс], 2021. Режим доступа:

https://www.typescriptlang.org/docs/handbook/declara tion-files/by-example.html (дата обращения: 12.09.2021).

2. Документация TypeScript / Type Inference / [Электронный ресурс], 2021. Режим доступа:

https://www.typescriptlang.org/docs/handbook/type-inference.html (дата обращения: 12.09.2021).

iНе можете найти то, что вам нужно? Попробуйте сервис подбора литературы.

3. Документация TypeScript / Advanced Types / [Электронный ресурс], 2021. Режим доступа: https://www.typescriptlang.org/docs/handbook/advanc ed-types.html (дата обращения: 11.09.2021).

4. Github репозиторий TypeScript / [Электронный ресурс], 2021. Режим доступа: https://github.com/microsoft/TypeScript/#readme (дата обращения: 10.09.2021).

5. Энциклопедия Stanford / Lambda Calculus / [Электронный ресурс], 2021. Режим доступа: https://plato.stanford.edu/entries/lambda-calculus/ (дата обращения: 09.09.2021).

6. Введение в лямбда-исчисление / Rau l Rojas / [Электронный ресурс], 2021. Режим доступа: https://personal.utdallas.edu/~gupta/courses/apl/lambd a.pdf (дата обращения: 09.09.2021).

МОДЕЛЮВАННЯ КОЛИВАНЬ КОРПУСУ БОЙОВОÏ ryCEH^HOÏ МАШИНИ В УМОВАХ Р1ЗКОГО ГАЛЬМУВАННЯ ТА РУШАННЯ З М1СЦЯ

Пестерев М.В.

ВШСЬКОВА АКАДЕМ1Я (М. ОДЕСА), АДЪЮНКТ

Мовчан В.В.

Житомирський вшськовий iнститут м. С.П. Корольова, викладач кафедри тактики та бойового забезпечення

SIMULATION OF OSCILLATIONS OF THE BODY OF THE COMBAT TRACK MACHINE IN THE CONDITIONS OF SHARP BRAKING AND MOVEMENT FROM THE PLACE

Pester ev M.

Odessa Military Academy, graduate student

Movchan V.

Zhytomyr Military Institute named after S.P. Korolyova, a lecturer at the Department of Tactics and Combat Support

АНОТАЦ1Я

В статл наведено моделювання коливань корпусу бойово! гусенично! машини (БГМ), як виклика-ються при И руа. Зокрема, продемонстроваш схеми сил, яш дшть на корпус машини, рiвняння та !х ршення, а також зроблеш ввдповщт висновки за результатами моделювання коливань машини, яш викли-каються динамiчним впливом гальмування та прискорення машини.

ABSTRACT

The article presents a simulation of the oscillations of the body of a combat tracked vehicle (BGM), which are caused by its movement. In particular, the schemes of forces acting on the body of the machine, equations and their solutions are demonstrated, as well as the corresponding conclusions are made based on the results of modeling the oscillations of the machine caused by the dynamic influence of braking and acceleration of the machine.

K^40Bi слова: бойова гусенична машина, коливальний рух, динамiчний вплив гальмування та при-скорення.

Keywords combat tracked vehicle, oscillating motion, dynamic effect of braking and acceleration.

Постановка проблеми. Важливою обстави-ною ввдсутносп навчально-тренувальних засобiв, яш орieнтованi на професiйну шдготовку ме-ханiкiв-водiiв е недостатньо повна теоретична база iмiтацiйного моделювання, яка повинна бути направлена на випуск тренажерiв та iмiтаторiв, орiентованих на напрацювання необхiдних про-фесiональних навишв керування бойовою гусенич-ною машиною. Це приводить до того, що iснуючi

на сьогоднi одно- та двухступеневi динамiчнi тре-нажери повшстю забезпечують виконання лише трьох навишв (навик щдготовки двигуна до пуску та його пуск; навик спостереження за показами кон-трольно-вимiрювальних прилащв та змiни режиму руху БГМ без перевантаження та перегрiву двигуна, навик гашення вертикальних та кутових коливань корпуса БГМ при подоланш нерiвностей або перешкод вертикального типу), в той час як го-ловш навики водiння (навик виконання рушання

i Надоели баннеры? Вы всегда можете отключить рекламу.