К тому же я не заметил в статье упоминания каких-либо механизмов кеширования вычислений
конечно же оно есть)
как только новая проекция сгенерирована, фрактал переходит в режим ожидания обновлений
вот тут имелось ввиду, что данные кешируются, пока не появятся изменения в зависимостях, принимавший участие в калькуляции. Да, не совсем явно получилось. Также стоит добавить, что после генерации новые данные поверхностно сравниваются с предыдущими и, если они эквивалентны, то они отбрасываются
Далее, я бы рекомендовал полностью инкапсулировать лоадеры.
я специально по максимуму вырезал всё кроме ядра, дабы показать показать нутро как есть, не скрывая ничего за абстракциями
Ни в коем случае не хотел вас как-то "задеть" ) не зашла шутка :)
В ваших примерах есть как раз "обмен данными между компонентами" в виде
while (true) yield `User ${yield* User}`
я так понимаю, что под обменом данных вы тут подразумеваете отдачу наверх через yield и получение от User через yield*, если так, то это скорее не обмен данных, а проброс вверх по дереву с предварительным маппингом.
Общение между собой фракталам не нужно, т.е. не нужно пробираться сквозь уровни parent-child, они не обмениваются данными.
под этим я подразумевал то, что в правильно построенной фрактальной архитектуре нам никогда не потребуется получать доступ к фракталам, которые являются детьми наших детей, т.е. App.User.Age и т.д.
Дальше Three опять будет подключен к какому-то фракталу, где его данные пройдут через эквивалент finallyGotSomeRelevantData и т.д. Вы пытаетесь извлечь выгоду из фрактала локально, для какой-то операции в контексте приложения с традиционным подходом, игнорируя главную суть — всё есть фрактал, всё приложение, каждый его кусочек. Продукт работы фрактала — это поток информации. Фракталами описывается всё дерево приложения от самого корня и до каждого листика.
В моей же схеме данные от User лежали бы в общедоступном хранилище, с ними удобно работать, нормализовывать, мутировать, создавать сложные селекторы…
Что-то почитал репозитории и, кажется, толковую дискуссию мы не создадим...
проблема в том, что я вашу схему полностью понимаю, но на мою вы похоже смотрите через призму своей, подсознательно сравнивая их, это не верно — между ними нет ничего общего — это два разных подхода, поверьте — я уважаю ваш выбор, и даже не думал вступать в спор о том у кого круче, скорее всего в статье у меня просто не получилось донести до вас ключевые моменты моей идеи
Не очень понял про то, как вы хотите одну сущность переводить одновременно в json и html — то есть в объектах описывать все возможные комбинации раскладки и атрибуты?
Вот этот пример fract.github.io/factors показывает как один и тот же фрактал в зависимости от фактора MODE выдает поток данных разного формата, исходники
Вот этот пример fract.github.io/antistress демонстрирует это в работе. Каждый фрактал приложения умеет отдавать и jsx, и json. Создаются два потока — jsx идет на экран, json в localStorage. Если вы откроете devtools, то увидите как данные обновляются одновременно с изображением на экране. Более того при перезагрузке состояние фрактала восстанавливается из последних сохраненных в localStorage данных. исходники
Под примесями я подразумевал html и css. Люблю просто писать код, а вот верстка, хоть и делаю хорошо и добросовестно, но это для меня то ещё мучение — минимум фантазии, просто стук по клавишам :)
Упустил, не раскрыл этот момент в статье.
Typescript потому, что без типов после одного большого проекта мне стало как-то тяжеловато.
Но тут все-таки «мясо» идеи не в генераторах, а в том, как смотреть на потоки данных.
Именно так. Генераторы с их возможностью ввода/вывода параметров по ходу выполнения просто оказались идеальными кандидатами для организации локаничного решения.
Я, честно говоря, все равно плохо понял, в чем преимущество перед реактивностью из Реакта.
Ни в чем, я не ставлю фрактал в противовес реакту, реактивность последнего во фрактальных приложениях попросту не используется, используется только рендеринг jsx -> html, что может быть заменено на гораздо более легковесную альтернативу.
Интеграцию именно с react я написал потому что это привычный для меня инструмент и естественно это первое, что пришло мне в голову, плюс ко всему — широкий охват желающих попробовать с минимумом усилий. Был бы я backend разработчиком — я бы в первую очередь написал интеграцию с чем-то серверным.
Разве что тут задается не только структура интерфейса, но и любых других данных
Всё правильно, фрактал задает общий стиль для описания любых данных и автоматически организует их "течение". Если рассматривать всё приложение как одно большое дерево с потоком данных, направленным к корню, то на листьях будут скорее всего примитивы, а на выходе из корня поток сложных структур, например jsx-снимков, которые отдаются реакту для рендера.
Продолжая разговор о генераторах и реакте, может не по теме, но могу привести некоторую параллель, смотрите — ниже два абсолютно идентичных компонента, первый реакт, второй фрактал
Реакт будет вызывать функцию Counter каждый раз, когда будет вызываться setCount, при этом useState по факту отработает полностью только при первом вызове, реакт отслеживает это внутри себя с помощью "магии" и при последующих вызовах реакт пропускает её, как бы имитирует то, что код сразу же выполняется с того места где я поставил восклицательный знак.
Фрактал просто идет до первого yield (по пути собирая зависимости, подключенные через yield*) отдает полученное значение в поток и ждёт изменений, как только дождался, код, благодаря генератору, просто продолжает своё выполнение c момента последней остановки до следующего yield и так по кругу. Никакой магии — всё последовательно и логично, но суть не в этом.
Не правда ли эти два компонента даже визуально на уровне кода выглядят очень похожими? Существенная разница здесь в том, что react компонент сильно ограничен тем, что должен использоваться только в составе jsx-кода и отдавать значение, соответствующее интерфейсу JSX.Element, в то время как фрактал может отдавать что угодно и использоваться в составе чего угодно.
Архитектурный астронавт — да, пожалуй это в точности про меня)
Я не презентую готовое решение всех проблем, я презентую идею и концепт, показывающий, как проблемы могли бы решаться.
Да, async это заметное падение производительности и быстродействие не конёк текущей реализации. Для того чтобы этот код шустро отрабатывал ему возможно необходима своя собственная среда выполнения, но поскольку это уже из области фантастики — я естественно рассматриваю варианты оптимизации, как использование синхронных генераторов там, где асинхронность не нужна и т.д.
Циклические зависимости — отдельная тема, архитектурно я не представляю кейса, когда это действительно нужно и дабы пресекать возможность случайного создания таких ситуаций с последующим долгим дебагом, я обдумываю механизм их отслеживания.
Я изобретаю велосипеды не от желания компенсировать узкость своего кругозора (а он на мой взгляд действительно узок). Я занимаюсь этим, потому что это часть моей жизни, мне без этого скучно, ну не могу я ни дня, чтоб чего нить не слепить :)
Спасибо! Да, на mandelbulb и ролики с её шедеврами я натыкался — действительно потрясающие виды, но попробовать самому поэкспериментировать с ней пока не доводилось. Тем не менее у меня это в заметках и я обязательно доберусь до этой программы.
В быту чаще всего мы используем генераторы для перебора некоторой последовательности значений, последовательность генерируется на лету, значения перебираются как правило в цикле либо spread-оператором
function* range(start, finish) {
do {
yield start++
} while (start <= finish)
return 'end of range'
}
for (const num of range(1, 3)) {
console.log(num)
}
/*
> 1
> 2
> 3
*/
const arr = [...range(1, 3)]
// [1, 2, 3]
В генераторе range мы указали return явно, но в действительности ни в первом, ни во втором варианте использования это попросту не нужно, поскольку по факту используется он только для прерывания процесса перебора, а возвращаемое им значение просто отбрасывается за ненадобностью.
Выражение yield* мы обычно используем, чтобы делегировать генерирование последовательности другому генератору, и практически никогда не используем его вторую особенность — получение return-значения. Попросту по тому, что не случается кейсов когда нам это действительно нужно. Это если рассматривать и использовать генераторы, как то для чего они предназначены — перебор коллекций.
function* range1to3() {
const returnValue = yield* range(1, 3)
// 'end of range' - но что с этим делать?
}
const arr = [...range1to3()]
// [1, 2, 3]
Но что если рассматривать и использовать их как обычные функции, не для перебора коллекций, а для обычного вычисления какого-то результата.
function* sum(one, two) {
return one + two
}
function* pifagor(one, two) {
return Math.sqrt(yield* sum(one ** 2, two ** 2))
}
тогда return будет использоваться привычным нам образом для возврата результата вычисления, а yield* для того чтобы этот результат получить, но при этом варианте использования за бортом остается yield — не понятно как тут задействовать его функционал, просто не видится кейсов.
Так вот во фрактале работает как раз второй вариант использования генераторов, а один из кейсов использования yield — обмен служебной информацией между уровнями вложенности.
const GET_PARENT = Symbol('parent query')
function wrap(gen) {
return function* wrapper() {
const parentName = yield GET_PARENT
console.log(`Calc ${gen.name} for ${parentName}`)
const iterator = gen()
let input
while (true) {
const { done, value } = iterator.next(input)
if (done) return value
if (value === GET_PARENT) {
input = gen.name
continue
}
throw 'unforeseen case'
}
}
}
const sum = wrap(function* (one, two) {
return one + two
})
const pifagor = wrap(function* (one, two) {
return Math.sqrt(yield* sum(one ** 2, two ** 2))
})
const main = wrap(function* () {
console.log(yield* pifagor(3, 4))
//> Calc pifagor for main
//> Calc sum for pifagor
//> 5
})
Очень надеюсь, что смог прояснить этот момент.
И ее связь с async-await, кстати.
Вот эта часть вашего вопроса мне не совсем понятна, поясните пожалуйста, что вы имели в виду.
Да, не очень, конечно, говорить про свой подход, когда вы ждете комментариев про свою идею
О нет нет! Своим комментарием вы прям всколыхнули волну воспоминаний о том, что я это всё прошёл. Не бахвальства ради, что впереди на шаг, но быть может мне удастся повернуть вас с этого пути в мою сторону, тем более — сами напросились :) Смотрите.
let one = { name: 'John' }
let two = `<input placeholder="Name" value="John">`
По вашему пути one — это данные (элемент стора), а two — это вид, они должны быть максимально разнесены в архитектуре приложения и общаться между собой через длинные адреса а-ля `store.any.data.from.the.universe`
По моему пути и one, и two — это одни и те же данные, только представленные в разных форматах, первый — json, второй — html.
Фрактал — это более абстрактная сущность, для которой что вид, что модель — всего лишь результат работы. Общение между собой фракталам не нужно, т.е. не нужно пробираться сквозь уровни parent-child, они не обмениваются данными.
Возможно мой ответ не удовлетворит ваши ожидания — я неуч, аббревиатура SICP меня ошарашила, как студента на экзамене, и её смысл, честно говоря, я узнал только с вашей подачи, погуглив естественно :)
Но тем не менее, начиная с последнего вопроса, постараюсь ответить так, как я это понимаю:
Поток — это некоторая последовательность порций информации.
Фрактал — это сущность, результатом работы которой является поток — последовательность порций информации, согласованной с его внутренним состоянием.
Каждая новая порция информации появляется в потоке в результате изменений, произошедших внутри фрактала — это реактивность.
Думаю, что первые 4 позиции тут-там периодически всем нам от проекта к проекту приходится юзать/реализовывать, и, в принципе, ничего особо интересного в этих находках нет, более того, как подметили некоторые комментаторы — есть более грамотные решения.
Зная это, можно написать функцию, позволяющую различать нативные и пользовательские функции
Ни разу не требовалось подобного, но очень хотелось бы увидеть реальный пример из практики. Заранее благодарю )
Всегда думал, что проблемы обходят меня стороной, но не сегодня www.youtube.com/watch?v=kuz4UCckmOE
Вот вам мой экзотический флексгейт. Сначала досада, потом нашел инфу, что запущена программа замены, мак в охапку, навигатор в сервис, приехал, показываю — они: ну как бы тут всё как во flexgate только у вас шлейф не тот сломался, надо чтоб именно подсветка пострадала, поэтому программа не для вас, вам сударь через кассу. Мзфк! Тим ты что творишь то?! Я $2700 уже отдал, ты не предупреждал что я еще 600 должен буду!
По моему тут всё же речь об одном множестве, второе это результат преобразования первого. Да их два, но исходно — одно
Фрактал это и есть та самая банальность, абстрактное множество, главная задача которого, как раз преобразование в разные виды множеств
Вы по сути, сами не заметив, четко и емко сформулировали суть :) Спасибо
конечно же оно есть)
вот тут имелось ввиду, что данные кешируются, пока не появятся изменения в зависимостях, принимавший участие в калькуляции. Да, не совсем явно получилось. Также стоит добавить, что после генерации новые данные поверхностно сравниваются с предыдущими и, если они эквивалентны, то они отбрасываются
я специально по максимуму вырезал всё кроме ядра, дабы показать показать нутро как есть, не скрывая ничего за абстракциями
Пожалуйста ))
тем не менее — время покажет)
P.S. спасибо за effector
С днем рождения?!
я там несколько суток точно оставил )
Ни в коем случае не хотел вас как-то "задеть" ) не зашла шутка :)
я так понимаю, что под обменом данных вы тут подразумеваете отдачу наверх через
yield
и получение отUser
черезyield*
, если так, то это скорее не обмен данных, а проброс вверх по дереву с предварительным маппингом.под этим я подразумевал то, что в правильно построенной фрактальной архитектуре нам никогда не потребуется получать доступ к фракталам, которые являются детьми наших детей, т.е. App.User.Age и т.д.
так нам, тоже никогда не потребуется делать, правильный эквивалент этого кода будет выглядеть так
Дальше
Three
опять будет подключен к какому-то фракталу, где его данные пройдут через эквивалентfinallyGotSomeRelevantData
и т.д. Вы пытаетесь извлечь выгоду из фрактала локально, для какой-то операции в контексте приложения с традиционным подходом, игнорируя главную суть — всё есть фрактал, всё приложение, каждый его кусочек. Продукт работы фрактала — это поток информации. Фракталами описывается всё дерево приложения от самого корня и до каждого листика.проблема в том, что я вашу схему полностью понимаю, но на мою вы похоже смотрите через призму своей, подсознательно сравнивая их, это не верно — между ними нет ничего общего — это два разных подхода, поверьте — я уважаю ваш выбор, и даже не думал вступать в спор о том у кого круче, скорее всего в статье у меня просто не получилось донести до вас ключевые моменты моей идеи
Вот этот пример fract.github.io/factors показывает как один и тот же фрактал в зависимости от фактора
MODE
выдает поток данных разного формата, исходникиВот этот пример fract.github.io/antistress демонстрирует это в работе. Каждый фрактал приложения умеет отдавать и jsx, и json. Создаются два потока — jsx идет на экран, json в localStorage. Если вы откроете devtools, то увидите как данные обновляются одновременно с изображением на экране. Более того при перезагрузке состояние фрактала восстанавливается из последних сохраненных в localStorage данных. исходники
С уважением )
Да, делим, и дальше в статье описывается как именно и что с этого получается ;)
Под примесями я подразумевал html и css. Люблю просто писать код, а вот верстка, хоть и делаю хорошо и добросовестно, но это для меня то ещё мучение — минимум фантазии, просто стук по клавишам :)
Упустил, не раскрыл этот момент в статье.
Typescript потому, что без типов после одного большого проекта мне стало как-то тяжеловато.
Именно так. Генераторы с их возможностью ввода/вывода параметров по ходу выполнения просто оказались идеальными кандидатами для организации локаничного решения.
Ни в чем, я не ставлю фрактал в противовес реакту, реактивность последнего во фрактальных приложениях попросту не используется, используется только рендеринг jsx -> html, что может быть заменено на гораздо более легковесную альтернативу.
Интеграцию именно с react я написал потому что это привычный для меня инструмент и естественно это первое, что пришло мне в голову, плюс ко всему — широкий охват желающих попробовать с минимумом усилий. Был бы я backend разработчиком — я бы в первую очередь написал интеграцию с чем-то серверным.
Всё правильно, фрактал задает общий стиль для описания любых данных и автоматически организует их "течение". Если рассматривать всё приложение как одно большое дерево с потоком данных, направленным к корню, то на листьях будут скорее всего примитивы, а на выходе из корня поток сложных структур, например jsx-снимков, которые отдаются реакту для рендера.
Продолжая разговор о генераторах и реакте, может не по теме, но могу привести некоторую параллель, смотрите — ниже два абсолютно идентичных компонента, первый реакт, второй фрактал
Реакт будет вызывать функцию
Counter
каждый раз, когда будет вызыватьсяsetCount
, при этомuseState
по факту отработает полностью только при первом вызове, реакт отслеживает это внутри себя с помощью "магии" и при последующих вызовах реакт пропускает её, как бы имитирует то, что код сразу же выполняется с того места где я поставил восклицательный знак.Фрактал просто идет до первого
yield
(по пути собирая зависимости, подключенные черезyield*
) отдает полученное значение в поток и ждёт изменений, как только дождался, код, благодаря генератору, просто продолжает своё выполнение c момента последней остановки до следующегоyield
и так по кругу. Никакой магии — всё последовательно и логично, но суть не в этом.Не правда ли эти два компонента даже визуально на уровне кода выглядят очень похожими? Существенная разница здесь в том, что react компонент сильно ограничен тем, что должен использоваться только в составе jsx-кода и отдавать значение, соответствующее интерфейсу
JSX.Element
, в то время как фрактал может отдавать что угодно и использоваться в составе чего угодно.Надеюсь, что пример получился удачным :)
Архитектурный астронавт — да, пожалуй это в точности про меня)
Я не презентую готовое решение всех проблем, я презентую идею и концепт, показывающий, как проблемы могли бы решаться.
Да, async это заметное падение производительности и быстродействие не конёк текущей реализации. Для того чтобы этот код шустро отрабатывал ему возможно необходима своя собственная среда выполнения, но поскольку это уже из области фантастики — я естественно рассматриваю варианты оптимизации, как использование синхронных генераторов там, где асинхронность не нужна и т.д.
Циклические зависимости — отдельная тема, архитектурно я не представляю кейса, когда это действительно нужно и дабы пресекать возможность случайного создания таких ситуаций с последующим долгим дебагом, я обдумываю механизм их отслеживания.
Я изобретаю велосипеды не от желания компенсировать узкость своего кругозора (а он на мой взгляд действительно узок). Я занимаюсь этим, потому что это часть моей жизни, мне без этого скучно, ну не могу я ни дня, чтоб чего нить не слепить :)
Спасибо за ссылку, я обязательно изучу этот материал.
Спасибо! Да, на mandelbulb и ролики с её шедеврами я натыкался — действительно потрясающие виды, но попробовать самому поэкспериментировать с ней пока не доводилось. Тем не менее у меня это в заметках и я обязательно доберусь до этой программы.
В быту чаще всего мы используем генераторы для перебора некоторой последовательности значений, последовательность генерируется на лету, значения перебираются как правило в цикле либо spread-оператором
В генераторе range мы указали
return
явно, но в действительности ни в первом, ни во втором варианте использования это попросту не нужно, поскольку по факту используется он только для прерывания процесса перебора, а возвращаемое им значение просто отбрасывается за ненадобностью.Выражение
yield*
мы обычно используем, чтобы делегировать генерирование последовательности другому генератору, и практически никогда не используем его вторую особенность — получение return-значения. Попросту по тому, что не случается кейсов когда нам это действительно нужно. Это если рассматривать и использовать генераторы, как то для чего они предназначены — перебор коллекций.Но что если рассматривать и использовать их как обычные функции, не для перебора коллекций, а для обычного вычисления какого-то результата.
тогда
return
будет использоваться привычным нам образом для возврата результата вычисления, аyield*
для того чтобы этот результат получить, но при этом варианте использования за бортом остаетсяyield
— не понятно как тут задействовать его функционал, просто не видится кейсов.Так вот во фрактале работает как раз второй вариант использования генераторов, а один из кейсов использования
yield
— обмен служебной информацией между уровнями вложенности.Очень надеюсь, что смог прояснить этот момент.
Вот эта часть вашего вопроса мне не совсем понятна, поясните пожалуйста, что вы имели в виду.
О нет нет! Своим комментарием вы прям всколыхнули волну воспоминаний о том, что я это всё прошёл. Не бахвальства ради, что впереди на шаг, но быть может мне удастся повернуть вас с этого пути в мою сторону, тем более — сами напросились :) Смотрите.
По вашему пути one — это данные (элемент стора), а two — это вид, они должны быть максимально разнесены в архитектуре приложения и общаться между собой через длинные адреса а-ля `store.any.data.from.the.universe`
По моему пути и one, и two — это одни и те же данные, только представленные в разных форматах, первый — json, второй — html.
Фрактал — это более абстрактная сущность, для которой что вид, что модель — всего лишь результат работы. Общение между собой фракталам не нужно, т.е. не нужно пробираться сквозь уровни parent-child, они не обмениваются данными.
Но тем не менее, начиная с последнего вопроса, постараюсь ответить так, как я это понимаю:
Поток — это некоторая последовательность порций информации.
Фрактал — это сущность, результатом работы которой является поток — последовательность порций информации, согласованной с его внутренним состоянием.
Каждая новая порция информации появляется в потоке в результате изменений, произошедших внутри фрактала — это реактивность.
Шел 2020 год…
Яндекс-Деньги больше не Яндекса деньги..)
Ни разу не требовалось подобного, но очень хотелось бы увидеть реальный пример из практики. Заранее благодарю )
www.youtube.com/watch?v=kuz4UCckmOE
Вот вам мой экзотический флексгейт. Сначала досада, потом нашел инфу, что запущена программа замены, мак в охапку, навигатор в сервис, приехал, показываю — они: ну как бы тут всё как во flexgate только у вас шлейф не тот сломался, надо чтоб именно подсветка пострадала, поэтому программа не для вас, вам сударь через кассу. Мзфк! Тим ты что творишь то?! Я $2700 уже отдал, ты не предупреждал что я еще 600 должен буду!