Конкатенативный стиль программирования

Полный пример про стрим-процессинг я решил пока не делать — в силу его довольно высокой сложности и слабой наглядности. Это пожалуй главный недостаток упомянутой архитектуры — сложность реализации.

Стрим-процессинг в общем случае подразумевает, что клиент отправляет команды в некое middleware, которое на самом деле никакой сложной логики не выполняет. Оно лишь неким предварительным образом обрабатывает входные команды, обновляет состояния, а главное, формирует из команд очередь сообщений. Основная обработка выполняется «процессорами» (они также нередко называются «агрегаторы»), которые подписываются на поток сообщений. Главная идея в том, что сами «процессоры» также могут формировать события, и таким образом и выстраивается нужная архитектура — наращиванием «процессоров», связанных через очередь сообщений.

В рамках нашей новой изменённой стратегии 2017 рассмотрим не архитектуру, а очередной стиль программирования — конкатенативный. Подразумевается, что клиент передаёт серверу некий workflow — непрерывный поток функций и значений, а тот осуществляет его интерпретацию.

Исходная наша тестовая последовательность команд записывается, напомню, так:

move 100
turn -90
set soap
start
move 50
stop

Перепишем её в постфиксной нотации и представим единой строкой-стримом:

100 move -90 turn soap set start 50 move stop

Это в принципе и всё, что требуется на клиентской стороне. Полностью файл client.py запишется так:

from cat_api import CatApi
api = CatApi()
s = api.exec('100 move -90 turn soap set start 50 move stop')

Функциональную часть — pure_robot.py, мы по-прежнему оставляем неизменной, что подтверждает правильность уже довольно давно выбранного подхода.

Как будет устроена серверная часть — класс CatApi? При инициализации в нём создается стек с одним элементом — начальным состоянием. Команда exec() создаёт так называемую «кучу» (входной поток вычислений), который будет последовательно сканироваться, и далее выполняет его интерпретацию. Сама интерпретация сводится к прозаическому применению очередного элемента кучи к текущему содержимому стека (функция compose()). Для наших управляющих команд (move, turn, …) функция compose извлекает (pop) из стека верхнее значение — параметр команды (если он требуется) и текущее состояние, и вызывает для них соответствующую функцию вычисления нового состояния, которое помещается обратно на верх стека (push). Если же очередной элемент кучи — обычное значение, оно просто помещается в стек. Вот и всё!

import pure_robotclass CatApi:    def __init__(self):        self.stack = [ pure_robot.RobotState(0.0, 0.0, 0, pure_robot.WATER) ]    def exec(self, code):        heap = code.split(' ')        for itm in heap:            self.compose(itm)                         if self.stack:            return self.stack[0]        return None    def compose(self, fn):        if fn=='move':            v = self.pop()            state = self.pop()            new_state = pure_robot.move(transfer,int(v), state)             self.push(new_state)        elif fn=='turn':            v = self.pop()            state = self.pop()            new_state = pure_robot.turn(transfer,int(v), state)             self.push(new_state)        elif fn=='set':            v = self.pop()            state = self.pop()            new_state = pure_robot.set_state(transfer,v, state)             self.push(new_state)        elif fn=='start':            state = self.pop()            new_state = pure_robot.start(transfer, state)             self.push(new_state)        elif fn=='stop':            state = self.pop()            new_state = pure_robot.stop(transfer, state)             self.push(new_state)        else:            self.push(fn)    def pop(self):        v = self.stack[-1]        self.stack.pop()        return v    def push(self, v):        self.stack.append(v)def transfer(message):    print (message)

Плюсы.
Реализация очень проста, наглядна и эффективна.
Мутабелен только стек, но прямого доступа к нему не требуется: он используется по сути только для промежуточных вычислений.

Минусы.
Исходные команды надо записывать в обратной польской нотации.

Поделиться статьей ...Share on Facebook0Share on Google+0Tweet about this on TwitterShare on LinkedIn0Share on VKPrint this page

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

Ваш e-mail не будет опубликован. Обязательные поля помечены *