All streams
Search
Write a publication
Pull to refresh
34
0
Денис @iminside

js nerd

Send message
А ведь всё что есть — это отображение множества в другое множество

По моему тут всё же речь об одном множестве, второе это результат преобразования первого. Да их два, но исходно — одно


Вот интересно, до каких пор «программисты» будут ацки извращаться, пока не поймут банальности?

Фрактал это и есть та самая банальность, абстрактное множество, главная задача которого, как раз преобразование в разные виды множеств


Вы по сути, сами не заметив, четко и емко сформулировали суть :) Спасибо

К тому же я не заметил в статье упоминания каких-либо механизмов кеширования вычислений

конечно же оно есть)


как только новая проекция сгенерирована, фрактал переходит в режим ожидания обновлений

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


Далее, я бы рекомендовал полностью инкапсулировать лоадеры.

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

Пожалуйста ))

тем не менее — время покажет)
P.S. спасибо за effector

Уже 12 часов ночи, пока я думал об этом всем, мне стукнуло 42.

С днем рождения?!

я там несколько суток точно оставил )

Ну вот не знаю про "шаг впереди".

Ни в коем случае не хотел вас как-то "задеть" ) не зашла шутка :)


В ваших примерах есть как раз "обмен данными между компонентами" в виде

while (true) yield `User ${yield* User}`

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


Общение между собой фракталам не нужно, т.е. не нужно пробираться сквозь уровни parent-child, они не обмениваются данными.

под этим я подразумевал то, что в правильно построенной фрактальной архитектуре нам никогда не потребуется получать доступ к фракталам, которые являются детьми наших детей, т.е. App.User.Age и т.д.


Promise.all(await exec(One), await exec(Two))
   .then(arr => arr.map(frame => frame.data))
   .then(finallyGotSomeRelevantData)

так нам, тоже никогда не потребуется делать, правильный эквивалент этого кода будет выглядеть так


const Three = fractal(async function*(){
    while(true) yield [yield* One, yield* Two]
})

Дальше 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-снимков, которые отдаются реакту для рендера.


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


function Counter() {
    const [count, setCount] = useState(0)
    // !
    return (
        <div>
            <p>Current value {count}</p>
            <button onClick={() => setCount(count + 1)}>Increment</button>
        </div>
    )
}

const Counter = fractal(async function* () {
    const Value = fraction(0)

    while (true) { // !
        const count = yield* Value

        yield (
            <div>
                <p>Current value {count}</p>
                <button onClick={() => Value.use(count + 1)}>Increment</button>
            </div>
        )
    }
})

Реакт будет вызывать функцию 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 меня ошарашила, как студента на экзамене, и её смысл, честно говоря, я узнал только с вашей подачи, погуглив естественно :)
Но тем не менее, начиная с последнего вопроса, постараюсь ответить так, как я это понимаю:
Поток — это некоторая последовательность порций информации.
Фрактал — это сущность, результатом работы которой является поток — последовательность порций информации, согласованной с его внутренним состоянием.
Каждая новая порция информации появляется в потоке в результате изменений, произошедших внутри фрактала — это реактивность.
Забавно, но ниже в разделе «Похожие публикации» выдается статья от 2007 года Яндекс стал 100% владельцем системы Яндекс-Деньги.

Шел 2020 год…
Яндекс-Деньги больше не Яндекса деньги..)
Думаю, что первые 4 позиции тут-там периодически всем нам от проекта к проекту приходится юзать/реализовывать, и, в принципе, ничего особо интересного в этих находках нет, более того, как подметили некоторые комментаторы — есть более грамотные решения.

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

Ни разу не требовалось подобного, но очень хотелось бы увидеть реальный пример из практики. Заранее благодарю )
Всегда думал, что проблемы обходят меня стороной, но не сегодня
www.youtube.com/watch?v=kuz4UCckmOE
Вот вам мой экзотический флексгейт. Сначала досада, потом нашел инфу, что запущена программа замены, мак в охапку, навигатор в сервис, приехал, показываю — они: ну как бы тут всё как во flexgate только у вас шлейф не тот сломался, надо чтоб именно подсветка пострадала, поэтому программа не для вас, вам сударь через кассу. Мзфк! Тим ты что творишь то?! Я $2700 уже отдал, ты не предупреждал что я еще 600 должен буду!

Information

Rating
Does not participate
Location
Ногинск, Москва и Московская обл., Россия
Date of birth
Registered
Activity