function attribute_effect(
	element,
	fn,
	thunks = [],
	css_hash,
	skip_warning = false,
	d = derived
) {
	const deriveds = thunks.map(d);

	/** @type {Record<string | symbol, any> | undefined} */
	var prev = undefined;

	/** @type {Record<symbol, Effect>} */
	var effects = {};

	var is_select = element.nodeName === 'SELECT';
	var inited = false;

	block(() => {
		var next = fn(...deriveds.map(get));

		set_attributes(element, prev, next, css_hash, skip_warning);

		if (inited && is_select && 'value' in next) {
			select_option(/** @type {HTMLSelectElement} */ (element), next.value, false);
		}

		for (let symbol of Object.getOwnPropertySymbols(effects)) {
			if (!next[symbol]) destroy_effect(effects[symbol]);
		}

		for (let symbol of Object.getOwnPropertySymbols(next)) {
			var n = next[symbol];

			if (symbol.description === ATTACHMENT_KEY && (!prev || n !== prev[symbol])) {
				if (effects[symbol]) destroy_effect(effects[symbol]);
				effects[symbol] = branch(() => attach(element, () => n));
			}
		}

		prev = next;
	});

	if (is_select) {
		init_select(
			/** @type {HTMLSelectElement} */ (element),
			() => /** @type {Record<string | symbol, any>} */ (prev).value
		);
	}

	inited = true;
}
@param {Element & ElementCSSInlineStyle} element
@param {(...expressions: any) => Record<string | symbol, any>} fn
@param {Array<() => any>} thunks
@param {string} [css_hash]
@param {boolean} [skip_warning]