URBI — введение в urbiScript — часть 3


1. введение в urbiScript — часть 1
2. введение в urbiScript — часть 2
3. введение в urbiScript — часть 3

Продолжаем рассмотрение возможностей скриптового языка urbiScript от компании Gostai, предназначенного для управления роботами.

Напомню, что urbiScript выполняется на Urbi-сервере, который запускается либо на роботе, либо на компьютере и к которому можно подключиться через сеть обычным telnet-ом.

16. Прототипное программирование в urbiScript

Для примера рассмотрим объект Pair — контейнер, который содержит две величины (first и second) и похож н std::pair в С++.

Pair;
[00000000] (nil, nil)

Видим, что Pair содержит две переменных, которые равны nil (по-умолчанию).
Клонируем Pair в свою переменную:

var p = Pair.clone;
[00000000] (nil, nil)
p.first = "101010";
[00000000] "101010"
p.second = true;
[00000000] true
p;
[00000000] ("101010", true)
Pair;
[00000000] (nil, nil)

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

var before = Pair.clone;
[00000000] (nil, nil)
Pair.first = false;
[00000000] false
var after = Pair.clone;
[00000000] (false, nil)
before;
[00000000] (false, nil)
// before и after имеют доступ к тому же значению first.
assert(Pair.first === before.first);
assert(Pair.first === after.first);

17. Псевдоклассы

Например, для определения своего класса Pair нужно создать объект с двумя слотами first и second (первый и второй).
Для этого можно использовать ключевое слово do

var MyPair = Object.clone;
[00000000] Object_0x1
do (MyPair)
{
	var first = nil;
	var second = nil;
	function asString ()
	{
	"MyPair: " + first + ", " + second
	};
} | {};
// создали свой объект Pair
MyPair;
[00000000] MyPair: nil, nil
// испытаем
var p = MyPair.clone;
[00000000] MyPair: nil, nil
p.first = 0;
[00000000] 0
p;
[00000000] MyPair: 0, nil
MyPair;
[00000000] MyPair: nil, nil

то же самое можно проделать используя ключевое слово class:

class MyPair
{
	var first = nil;
	var second = nil;
	function asString() { "(" + first + ", " + second + ")"; };
};
[00000000] (nil, nil)

Т.е. ключевое слово class просто создаёт объект MyPair, клонируя Object и предоставляет оболочку do.

18. Конструктор
Некоторые классы поддерживают конструкторы, доступные через метод new (вместо метода clone), принимающего передаваемые параметры.

var p = Pair.new("foo", false);
[00000000] ("foo", false) 

Т.о. получается, что clone гарантирует получение пустого объекта, наследуемого от прототипа.
метод new по-умолчанию делает то же самое, но позволяет сразу задавать новые атрибуты объекта.

Для определения конструктора, прототипу достаточно иметь функцию init, которая будет вызвана с параметрами, переданными методу new.
Добавим конструктор классу MyPair из предыдущего примера:

class MyPair
{
	var first = nil;
	var second = nil;
	function init(f, s) { first = f; second = s; };
	function asString() { "(" + first + ", " + second + ")"; };
};
[00000000] (nil, nil)
MyPair.new(0, 1);
[00000000] (0, 1)

19. Операторы

urbiScript поддерживает перегрузку операторов.

class ArithPair
{
	var first = nil;
	var second = nil;
	function init(f, s) { first = f; second = s; };
	function asString() { "(" + first + ", " + second + ")"; };
	function '+'(rhs) { new(first + rhs.first, second + rhs.second); };
	function '-'(rhs) { new(first - rhs.first, second - rhs.second); };
	function '*'(rhs) { new(first * rhs.first, second * rhs.second); };
	function '/'(rhs) { new(first / rhs.first, second / rhs.second); };
};
[00000000] (nil, nil)
ArithPair.new(1, 10) + ArithPair.new(2, 20) * ArithPair.new(3, 30);
[00000000] (7, 610)

20.

Для того чтобы вставить в объект функцию нужно использовать метод setSlot:

var o = Object.clone | {};
// Here we can use f as any regular value
o.setSlot("m1", function () { echo("Hello") }) | {};
// This is strictly equivalent
var o.m2 = function () { echo("Hello") } | {};
o.m1;
[00000000] *** Hello
o.m2;
[00000000] *** Hello

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

function all(list, predicate)
{
	for (var elt : list)
		if (!predicate(elt))
			return false;
	return true;
} | {};
// проверим являются ли все элементы списка положительными
function positive(x) { x >= 0 } | {};
all([1, 2, 3], getSlot("positive"));
[00000000] true
all([1, 2, -3], getSlot("positive"));
[00000000] false

Метод all уже существует. Его можно вызвать

list.all(predicate)

21. Лямбда-функции
Лямбда-функция — это функция не привязанная к конкретному имени (их удобно использовать в функциях в качестве callback-параметра ).

Пример создания такой анонимной функции в urbiScript:

// создание анонимной функции
function (x) {x + 1} | {};
// создание такой функции позволяет на лету
// передать её в качестве параметра метода "all":
[1, 2, 3].all(function (x) { x > 0});
[00000000] true

22. Ленивые аргументы (Lazy arguments)

в urbiScript по-умолчанию аргументы функции задаются точно, но с помощью объекта call можно вручную получить доступ к переданным аргументам функции.

// аргументы функции не указываются
function first
{
	// вызываем первый аргумент
	call.evalArgAt(0);
} | {};
first(echo("first"), echo("second"));
[00000000] *** first
function reverse
{
	call.evalArgAt(1);
	call.evalArgAt(0);
} | {};
reverse(echo("first"), echo("second"));
[00000000] *** second
[00000000] *** first

Отличный пример — логический оператор:

function myAnd
{
	if (call.evalArgAt(0))
		call.evalArgAt(1)
	else
		false;
}|;
function f()
{
	echo("f executed");
	return true;
}|;
myAnd(false, f());
[00000000] false
myAnd(true, f());
[00000000] *** f executed
[00000000] true

Читать далее: введение в urbiScript — часть 4


Добавить комментарий

Arduino

Что такое Arduino?
Зачем мне Arduino?
Начало работы с Arduino
Для начинающих ардуинщиков
Радиодетали (точка входа для начинающих ардуинщиков)
Первые шаги с Arduino

Разделы

  1. Преимуществ нет, за исключением читабельности: тип bool обычно имеет размер 1 байт, как и uint8_t. Думаю, компилятор в обоих случаях…

  2. Добрый день! Я недавно начал изучать программирование под STM32 и ваши уроки просто бесценны! Хотел узнать зачем использовать переменную типа…

3D-печать AI Arduino Bluetooth CraftDuino DIY Google IDE iRobot Kinect LEGO OpenCV Open Source Python Raspberry Pi RoboCraft ROS swarm ИК автоматизация андроид балансировать бионика версия видео военный датчик дрон интерфейс камера кибервесна манипулятор машинное обучение наше нейронная сеть подводный пылесос работа распознавание робот робототехника светодиод сервомашинка собака управление ходить шаг за шагом шаговый двигатель шилд юмор

OpenCV
Робототехника
Будущее за бионическими роботами?
Нейронная сеть - введение