CSS को एक query language की तरह देखना
(evdc.me)- CSS selectors और declarations संरचनात्मक रूप से Datalog के काफ़ी करीब हैं, क्योंकि वे पहले से मौजूद elements के एक set को चुनते हैं और उस result पर properties लागू करते हैं; Datalog भी relations को query करके facts बनाता है
- सामान्य CSS selection result को दोबारा selection condition के रूप में इस्तेमाल करने वाली recursive computation को support नहीं करता, इसलिए वह ऐसी state propagation को सीधे व्यक्त नहीं कर सकता जिसमें dark theme descendants तक फैले लेकिन light boundary पर रुक जाए
- काल्पनिक CSSLog में ऐसी class जोड़ने की अनुमति होगी जो selector matching को प्रभावित करे, जिससे
.effectively-darkजैसी derived state को recursively propagate किया जा सके, और computation तब तक दोहराई जाए जब तक कोई नया result न बचे - इस तरह की computation को Datalog के fixpoint और monotonicity से समझाया जाता है; iteration के finitely खत्म होने के लिए facts को हटाने के बजाय सिर्फ़ जोड़ना चाहिए
- वास्तविक CSS की container queries ancestor state को पढ़ तो सकती हैं, लेकिन derived recursive state को query नहीं कर सकतीं; इसलिए CSS, Datalog के क़रीब पहुँचकर भी browser rendering engine की सीमा पार नहीं करता
CSS और Datalog का बुनियादी correspondence
- CSS पहले से मौजूद targets को मानकर चलता है, और यहाँ वे target HTML elements हैं
h1,a,divजैसे elements CSS के बाहर पहले से मौजूद होते हैं; CSS उन्हें नया declare नहीं करता- उदाहरण के तौर पर
class,id,data-custom-attributeजैसी attributes वाले elements दिखाए गए हैं
- CSS selectors साझा conditions वाले set को दर्शाते हैं, और tag name, id, class, attribute value से target को सीमित कर सकते हैं
div,#child,.awesome,[data-custom-attribute="foo"]जैसे selectors उदाहरण में आते हैं- document hierarchy के अंदर position relationship से भी target व्यक्त किया जा सकता है, और selectors को जोड़कर intersection भी बनाया जा सकता है
div.awesomeजैसा combined selector set intersection करता है, यानी सिर्फ़ वे elements चुने जाते हैं जोdivभी हों और.awesomeभी- यही intersection आगे चलकर Datalog के join से जुड़ने वाली अहम अवधारणा बनती है
- CSS rule selector और declaration को जोड़कर चुने गए set पर property values लागू करता है
div.awesome { color: red; font-size: 24px }उदाहरण में उन elements काcolorऔरfont-sizeसेट होता है- browser में उसका result बड़े लाल text के रूप में render होता है
CSS की सीमाएँ और recursive query की समस्या
- सामान्य CSS language के बाहर की properties बदलने में मज़बूत है, लेकिन उन बदलावों के result को फिर सीधे selection condition के रूप में इस्तेमाल नहीं कर सकता
- element का color सेट किया जा सकता है, लेकिन
div[color=red]की तरह color को ही selector condition बनाना browser अस्वीकार कर देता है color: redवाले element पर फिरcolor: blueलगाने वाला rule अर्थ की दृष्टि से अस्पष्ट हो जाएगा
- element का color सेट किया जा सकता है, लेकिन
- design system का dark mode उदाहरण transitive state propagation की माँग करने वाली समस्या के रूप में दिया गया है
data-theme="dark"वाले card के अंदर सभी interactive elements पर white focus outline लागू करनी है- लेकिन बीच में
data-theme="light"आ जाए तो उसके नीचे propagation रुक जानी चाहिए
- वास्तविक CSS में exceptions जोड़ने के तरीके से सिर्फ़ कुछ हद तक इसे संभाला जा सकता है
[data-theme="dark"] :focus { outline-color: white; }से base rule बनाया जा सकता है[data-theme="dark"] [data-theme="light"] :focus { outline-color: black; }से light boundary को वापस पलटा जा सकता है- लेकिन nesting गहरी होती जाए तो नए rules लगातार जोड़ने पड़ते हैं
- इस समस्या के लिए recursive relational definition चाहिए, लेकिन CSS उसे व्यक्त नहीं कर सकता
- परिभाषा कुछ ऐसी चाहिए: “या तो वह ख़ुद dark हो, या उसका कोई effectively-dark ancestor हो और बीच में कोई effectively-light ancestor न हो, तब वह effectively-dark है”
- मूल लेख इसे recursive relational definition कहता है और साफ़ कहता है कि CSS इसे व्यक्त नहीं कर सकता
CSSLog की काल्पनिक syntax
- CSSLog को सामान्य CSS की तरह selectors और property setting बनाए रखते हुए, उन properties को बदलने वाला काल्पनिक version बताया गया है जो selector matching को प्रभावित करती हैं
- उदाहरण में
class: +barजैसा class जोड़ने वाला syntax आता है +<div class="baz">जैसी form से नया child element बनाने की भी कल्पना की गई है- element deletion के बारे में सिर्फ़ इतना लिखा है कि “शायद नहीं होना चाहिए”, अतिरिक्त विवरण नहीं है
- उदाहरण में
div.foorule चलने के बाद वही elementdiv.barसे भी match करने लगे, इस तरह rule execution का result अगली matching को प्रभावित करता है- यहाँ computation एक बार के forward application पर खत्म नहीं होती, बल्कि repeated evaluation की ज़रूरत पड़ती है
- dark mode उदाहरण को CSSLog में लाने पर derived class की recursive propagation संभव हो जाती है
[data-theme="dark"] { class: +effectively-dark; }से शुरुआत होती है.effectively-dark > :not([data-theme="light"]) { class: +effectively-dark; }से यह children तक propagate होता है.effectively-dark :focus { outline-color: white; }से अंतिम style लागू होती है
- दूसरा rule light boundary तक recursively propagate करता है और desired state आने पर रुक जाता है
- मूल लेख कहता है कि मौजूदा CSS से ऐसा behavior संभव नहीं है, और अंत में कुछ मिलते-जुलते workarounds पर फिर लौटता है
Datalog की संरचना और CSS से समानता
- Datalog में targets को atoms कहा जाता है, और वे पहली बार उल्लेख होते ही अस्तित्व में माने जाते हैं
alice,bobजैसे नाम बिना अलग declaration के सीधे इस्तेमाल होते हैं- साथ में Ruby के
:symbolsसे तुलना भी की गई है
- sets और relationships को relations और tuples से व्यक्त किया जाता है
parent(alice, bob)parentrelation के भीतर एक tuple हैparentको उन जोड़ियों के set के रूप में समझाया गया है जहाँ पहला target दूसरे target का parent है
- variables का इस्तेमाल query matching और set selection के लिए होता है
parent(bob, X)का मतलब है वे सभीXजिनके parent Bob हैं- इस उदाहरण में
Xका resultcarolऔरdaveआता है - प्रथा के तौर पर variables uppercase में और atoms व relations lowercase में लिखे जाते हैं
- वही variable name दोहराने पर join होता है
mother(X, Y) :- parent(X, Y), woman(X).parent set और woman set के intersection से mother relation बनाता है- लेख इसे “सभी parents” और “सभी women” के intersection की तरह समझाता है
- Datalog rule का
:-if की तरह पढ़ा जाता है; जब दाहिनी ओर के body conditions सब सच हों, तब बाईं ओर का head fact true के रूप में जोड़ा जाता है- body में comma को and की तरह पढ़ा जाता है
ancestor(X, Y) :- parent(X, Y).का अर्थ है: अगर X, Y का parent है, तो X उसका ancestor है
- CSS और Datalog की तुलना उलटी हुई लेकिन समान संरचना के रूप में की गई है
color(X, red) :- div(X), class(X, awesome).का अर्थ होगा “जो Xdivहै औरawesomeclass रखता है, उसका color red है”- इसे CSS के
div.awesome { color: red; }के semantic counterpart के रूप में दिखाया गया है - मूल लेख निष्कर्ष निकालता है कि selector body है और declaration head
Recursion और derived facts
- Datalog में कुछ “करने” का मतलब नए facts derive करना है
- यह existing facts के आधार पर relation में नए tuples जोड़कर काम करता है
ancestorउदाहरण recursive rule का आदर्श मामला हैancestor(X, Y) :- parent(X, Y).direct parent को ancestor बनाता हैancestor(X, Y) :- parent(X, Z), ancestor(Z, Y).parent के ancestor relation का पीछा करते हुए ऊपर तक फैलाता है
- दूसरा rule
ancestorके head और body दोनों में आने वाली self-referential recursion रखता है- इससे
alice -> bob -> carol,alice -> bob -> daveजैसी indirect ancestor relationships derive होती हैं
- इससे
- उदाहरण के execution result में ये पाँच facts दिए गए हैं
ancestor(alice, bob)ancestor(bob, carol)ancestor(bob, dave)ancestor(alice, carol)ancestor(alice, dave)
- SQL भी
WITH RECURSIVEसे पहले ऐसी computation नहीं कर पाता था, और लेख के अनुसार यह feature recursive computation की माँग के कारण आया- हालाँकि लेख यह भी जोड़ता है कि SQL की recursive syntax और semantics हमेशा बाकी हिस्सों के साथ अच्छी तरह compose नहीं होतीं
- Datalog में
forloop के बिना भी engine जब तक सारे ज़रूरी results न निकल आएँ तब तक computation जारी रखता है- अगला section इसका कारण fixpoint से जोड़ता है
Fixpoint और monotonicity
- सामान्य CSS का cascade एक बार की forward application की तरह बताया गया है
- browser rules पढ़ता है, selector matching compute करता है, declarations लागू करता है, और काम खत्म हो जाता है
- कोई feedback loop नहीं होता
- CSSLog और वास्तविक Datalog में किसी rule का result दूसरे rule की condition को फिर से satisfy करा सकता है
- कोई rule property बदलता है, उसी property की वजह से दूसरा rule फिर चल सकता है, और फिर उसका असर पहले rule तक भी लौट सकता है
- एक naïve Datalog engine जब तक कोई नया fact न बचे तब तक rules को बार-बार लागू करता है
- वह declared base facts से शुरू करता है
- सभी rules के body को मौजूदा facts के set से match करता है
- match होने पर head fact जोड़ता है
- नया fact मिले तो फिर दोहराता है, नहीं मिले तो रुक जाता है
- इस रुकने की स्थिति को fixpoint कहा जाता है
- यानी वह state जहाँ सभी rules फिर से चलाने पर भी कोई नया result नहीं निकलता
ancestorउदाहरण को तीन rounds में समझाया गया है- पहले round में
parentfacts से direct ancestor relation के तीन facts जुड़ते हैं - दूसरे round में
aliceके दो indirect ancestor relations जुड़ते हैं - तीसरे round में कोई नया fact नहीं बनता और fixpoint आ जाता है
- पहले round में
- termination संभव होने का कारण monotonicity है
- facts हटाए नहीं जाते, सिर्फ़ जोड़े जाते हैं; इसलिए known facts का set लगातार बढ़ता ही है
- finite starting facts और finite derivation possibilities होने पर finite काम के बाद रुकना संभव है
- उल्टा, अगर facts हटाने की अनुमति हो तो बाद के result पहले के result को पलट सकते हैं, और यह गुण टूट जाता है
- मूल लेख इसे Infinite Loop Land कहता है, और इसी से जोड़कर बताता है कि CSSLog में element deletion की अनुमति न देना बेहतर होगा
- footnote में यह भी जोड़ा गया है कि distributed systems में monotonicity महँगे coordination के बिना consistency पाने के गुण से जुड़ी होती है
- Consistency As Logical Monotonicity संबंधित लिंक 1: distributed systems और monotonicity
- संबंधित शोध-पत्र लिंक 2: अतिरिक्त संदर्भ
यह महत्वपूर्ण क्यों है
- CSS और Datalog की तुलना अलग-अलग क्षेत्रों में एक ही संरचना को उजागर करती है
- दोनों में targets होते हैं, उन targets के sets को query किया जाता है, और फिर result के आधार पर कुछ लागू किया जाता है या नए facts बनाए जाते हैं
- Datalog और Prolog 1970 के दशक से relational databases और उस समय के AI research में दिखाई देते रहे हैं, और बाद में कई रूपों में फिर उभरे
- Datomic
- Differential Datalog
- साथ में कई rule engines का भी उल्लेख है
- इसमें यह observation है कि अगर आप ऐसा system बनाते हैं जिसमें targets हों, sets को describe करने की क्षमता हो, और उन targets पर operations किए जा सकें, तो वह समान निष्कर्षों की ओर converge करता है
- database/logic programming और frontend web development के क्षेत्र अक्सर एक-दूसरे से नहीं जुड़ते
- लेख उम्मीद जताता है कि अगर ये ज़्यादा जुड़ें तो मिलकर कुछ नया बनाया जा सकता है
Container Queries और वास्तविक CSS की सीमा
- यह चर्चा वास्तविक CSS feature Container Queries से भी जुड़ती है
- इनके ज़रिए parent या ancestor element की style के आधार पर current element पर style लागू की जा सकती है
- उदाहरण के रूप में
@container style(--theme: dark) { .card { background: royalblue; color: white; } }दिया गया है
- लेकिन transitive dark mode की समस्या सिर्फ़ ancestor lookup से अधिक शक्तिशाली computation माँगती है
- हर element को पता होना चाहिए कि वह effectively dark है या नहीं
- वह state descendants तक transitively propagate होनी चाहिए
- और
data-theme="light"boundary पर propagation रुकनी चाहिए
- Container queries derived state को नहीं पढ़ सकतीं
- वे ancestor की custom property value देख सकती हैं, लेकिन किसी दूसरे rule द्वारा पहले से compute की गई
effectively-darkजैसी state को query नहीं कर सकतीं - वे सिर्फ़ DOM में पहले से मौजूद state पढ़ सकती हैं; recursive computation का result नहीं
- वे ancestor की custom property value देख सकती हैं, लेकिन किसी दूसरे rule द्वारा पहले से compute की गई
- इसलिए “अगर कोई ancestor transitively dark है और उससे अधिक नज़दीक कोई light ancestor नहीं है, तो apply करो” जैसी query recursion माँगती है, इसलिए implement नहीं की जा सकती
- मूल लेख साफ़ कहता है कि container queries में recursion नहीं है
- 2015 article में बताया गया है कि element queries मिलते-जुलते कारणों से बार-बार क्यों विफल हुईं
- अगर query जिन properties को सेट करती है, उन्हीं को फिर query किया जा सके, तो loops और आगे चलकर infinite loops बन सकते हैं
- CSS Working Group ने ऐसी समस्याओं को information flow की direction सीमित करके हल किया है
- descendants ancestors की जानकारी query कर सकते हैं, लेकिन उलटी दिशा नहीं
- इससे fixpoint semantics के बिना भी finiteness बनाए रखी जा सकती है
- information सिर्फ़ tree के नीचे की दिशा में propagate होती है और structure ऐसा रहता है कि कोई नए base facts नहीं डाले जाते
- मूल लेख इस प्रवाह को ऐसे दिखाता है कि CSS, Datalog engine के क़रीब पहुँचते हुए भी जानबूझकर वहाँ तक नहीं जाता
- CSSLog का पक्ष चक्रों की अनुमति देकर fixpoint तक evaluate करने का है
- जबकि वास्तविक CSS इस सीमा पर रुकता है कि browser rendering engine कोई incremental relational database engine नहीं है
दूसरी दिशा की संभावनाएँ
- browser में Datalog semantics डालने के बजाय, Datalog के ऊपर CSS syntax चढ़ाने की दिशा भी संभव है
- Datalog का
:-, period, uppercase/lowercase conventions, assignment statements का अभाव जैसी बातें आधुनिक language users के लिए entry barrier बन सकती हैं
- Datalog का
- CSS के पास पहले से tree structure को सीधे संभालने वाली syntax है
- descendant, child, sibling combinators parent-child relation को स्वाभाविक रूप से व्यक्त करते हैं
- साधारण Datalog में ऐसी संरचना को relational form में कुछ असुविधाजनक तरीके से encode करना पड़ता है
- लेख ज़ोर देता है कि बहुत-सा वास्तविक data tree form में होता है
- JSON
- AST
- file system
- org chart
- XML उदाहरण के रूप में सूचीबद्ध हैं
- अगर कोई tool fixpoint recursion, CSS-style syntax और implicit parent-child relationships को जोड़ दे, तो recursive tree queries अधिक परिचित notation में लिखी जा सकती हैं
- लेख के अनुसार अब तक शायद किसी ने ऐसा tool ठीक से नहीं बनाया है
- अंत में यह सुझाव दिया गया है कि कोई व्यक्ति बेहतर नाम वाले “CSSLog” जैसा कुछ बना सकता है
Footnotes
- HTML elements की simplification पर एक footnote है
- संभावित आपत्ति यह हो सकती है that CSS जिन targets से काम करता है वे सभी ज़रूरी नहीं कि सिर्फ़ HTML elements हों, लेकिन लेख में सरलता के लिए उन्हें HTML elements मान लिया गया है
- naive evaluation हर बार पहले से known facts को भी फिर compute करती है, इसलिए inefficient होती है
- standard improvement के रूप में semi-naive evaluation का उल्लेख है
- इसका मूल विचार यह है कि हर चरण में सिर्फ़ नए derive हुए facts देखे जाएँ
- यह भी जोड़ा गया है कि infinite loops Turing-complete languages में कोई अनोखी बात नहीं हैं
- JavaScript में भी
while true {}लिखा जा सकता है - लेकिन web page की logic confusion की वजह से browser rendering system हमेशा के लिए रुक जाए, यह स्थिति टालना बेहतर है
- JavaScript में भी
- CSS की custom property inheritance workaround पर भी footnote में चर्चा है
[data-theme="dark"] { --effective-theme: dark; }[data-theme="light"] { --effective-theme: light; }@container style(--effective-theme: dark) { :focus { outline-color: white; } }- यह तरीका इस खास case में काफ़ी हद तक काम करता है, लेकिन inheritance असली transitive closure के बराबर नहीं है
- अधिक जटिल समस्याओं में, जहाँ parent-child के अलावा किसी और property chain के साथ transitive closure चाहिए, यह तरीका टूट जाता है
1 टिप्पणियां
Hacker News टिप्पणियाँ
CSS selectors को XPath की तुलना में लिखना बहुत आसान है
हाल ही में PHP के नए DOM API पर एक प्रस्तुति भी थी, जिसमें बताया गया कि अब HTML और CSS selectors को native तौर पर बहुत आसानी से हैंडल किया जा सकता है। पहले CSS को XPath में बदलना पड़ता था
[1] https://speakerdeck.com/keyvan/parsing-html-with-php-8-dot-4...
अफ़सोस है कि यह ब्राउज़र styling-केंद्रित तरीके से विकसित हुआ, इसलिए इसमें XPath जैसी text content आधारित selection जैसी सुविधाएँ नहीं हैं
मुझे पता है कि पहले इसके प्रस्ताव आए थे, लेकिन ब्राउज़र rendering context में performance समस्याएँ आ सकती थीं, इसलिए शायद यह spec में शामिल नहीं हो पाया
एक document editing agent बनाते समय मैंने दस्तावेज़ को HTML के रूप में दिखाया और LLM से सिर्फ़ CSS selector निर्दिष्ट करवाकर ज़रूरी हिस्से context में खींचने दिए, और यह लगभग जादू की तरह काम करता था
लोग उसी परिचित तरीके से इसे इस्तेमाल कर सकते हैं
काश CSS grammar और CSSWG द्वारा परिभाषित rules, functions, units जैसी पूरी प्रणाली को अलग से बुलाने के लिए कोई नाम होता
इसमें काफ़ी संभावना है, लेकिन दूसरे use cases पर बात करने या उन्हें खोजने के लिए आख़िरकार GitHub के उस कोड को खंगालना पड़ता है जिसमें CSS parser शामिल हो, ताकि पता चल सके कि लोग कैसी अजीब चीज़ें बना रहे हैं
मैं कुछ वैसा भी छेड़छाड़ कर रहा हूँ जो किसी अजीब template engine जैसा है, जिसमें हल्की node-आधारित markup language, template में क्या जाएगा यह व्यक्त करने वाले CSS selectors, और इन टुकड़ों को कैसे जोड़ा जाए इसे नियंत्रित करने वाला CSS-जैसा grammar मिला हुआ है
https://www.w3.org/TR/selectors-3/
DOM spec भी इसी का संदर्भ देती है
https://dom.spec.whatwg.org/#selectors
इसलिए CSS selector एक umbrella term के रूप में पहले से सही है, और इसे सिर्फ़ selector भी कहा जा सकता है
DOM selector नाम और साफ़ लग सकता है, लेकिन अगर static CSS में इस्तेमाल होने वाले selectors या JS engine के बाहर के दूसरे DOM engines (XML parser, PHP DOM API आदि) के selectors को भी सोचें, तो यह उल्टा और भ्रमित कर सकता है
साथ ही
:hoverया::target-textजैसे ऐसे special selectors भी हैं जो सीधे ब्राउज़र rendering/navigation से जुड़े हैंफिर भी, ब्राउज़र या CSS से कम जुड़े हुए न्यूनतम query grammar subset के लिए अलग नाम होना उपयोगी हो सकता है
मुझे पुराने conference में देखा हुआ https://github.com/braposo/graphql-css याद आ गया
यह मज़ाकिया project था, लेकिन यह अच्छी तरह दिखाता था कि patterns को दूसरे contexts में transplant करके दोबारा इस्तेमाल करने का तरीका अप्रत्याशित चीज़ों को संभव बना सकता है
मैं भी ठीक इसी तरह अलग contexts के patterns उठाकर आज़माने की कोशिश कर रहा हूँ
ज़्यादातर चीज़ें शायद कहीं दूर तक न जाएँ, फिर भी hacker संवेदना के हिसाब से यह काफ़ी दिलचस्प है
pyastgrep में, जैसा कि https://pyastgrep.readthedocs.io/en/latest/ पर दिखता है, Python grammar को query करने के लिए CSS selectors इस्तेमाल किए जा सकते हैं
default XPath है, और उदाहरण के लिए
pyastgrep --css 'Call > func > Name#main'जैसा इस्तेमाल संभव हैयह लगभग ठीक उसी दिशा से मेल खाता है जिसकी ओर मैं इशारा करना चाहता था
मुझे ठीक से समझ नहीं आ रहा कि यह किस scenario को हल करता है
अभी भी child के आधार पर parent को conditionally बदला जा सकता है। उदाहरण के लिए
preकी default padding 16px है, और अगर उसका direct childcodeहै तो&:has(> code)से इसे 0 किया जा सकता हैनिष्कर्ष भी "आधुनिक CSS की सीमाओं को ठीक करना चाहिए" से ज़्यादा इस बात के करीब है कि शायद CSS-जैसा grammar किसी Datalog-जैसी system पर चढ़ाने से tree-आकृति वाले data को संभालना ज़्यादा इंजीनियरों के लिए परिचित बनाया जा सकता है
यानी बात DOM में नए child elements या attributes जोड़ने की है
मौजूदा LLM CSS को बहुत अच्छी तरह नहीं संभालते, इसलिए उल्टा यह आज़माकर देखना दिलचस्प होगा कि क्या इससे LLM ज़्यादा सरल तरीके से reason कर पाते हैं
इसका कोई वास्तविक उपयोग तुरंत नहीं सूझता, लेकिन यह फिर भी काफ़ी cool है
हम्म... कहीं यह बस JQ तो नहीं है?
मुझे CSS कुछ हद तक पसंद है, लेकिन इसकी बढ़ती हुई complexity creep पसंद नहीं
मैं समझता हूँ कि programming languages, non-programming languages से ज़्यादा शक्तिशाली हो जाती हैं, लेकिन HTML, CSS और JavaScript को लगातार और जटिल बनाने की बजाय शायद बेहतर होता कि कुछ और आकर पूरे सेट को replace कर देता
HTML5 के नए elements भी क्यों ज़रूरी हैं, यह मुझे ज़्यादातर समझ नहीं आता, इसलिए मैं उन्हें शायद ही कभी इस्तेमाल करता हूँ। आख़िर में कई containers बस unique ID लगे
divही लगते हैं, और कभी-कभी लगता था कि internal link के लिएhrefnavigation हेतु उन IDs के aliases जैसे कुछ होने चाहिए थे[data-theme="dark"] [data-theme="light"] :focus { outline-color: black; }जैसी चीज़ को दिमाग़ में parse करने में बहुत समय लगता है, इसलिए यह अब elegant या simple नहीं लगतीदूसरी तरफ़
h2 { color: red; }अब भी simple हैancestor(X, Y) :- parent(X, Y).जैसा expression देखते ही सोचने का मन नहीं करता।:-आख़िर है क्या, मुस्कुराते चेहरे जैसा दिखता है@container style(--theme: dark) { .card { background: royalblue; color: white; } }पर तो मैंने पढ़ना ही छोड़ दियाअजीब लगता है कि जो standard पहले ठीक काम करता था, वह समय के साथ बिगड़ता जा रहा है
उदाहरण के लिए
[data-theme="dark"] [data-theme="light"] :focus { outline-color: black; }को अंग्रेज़ी जैसी pseudocode में खोलें तो इसका मतलब लगभग यह है कि अगरdata-theme="dark"वाला X है, उसका child Ydata-theme="light"है, और वह focus स्थिति में है, तो Y काoutline-colorblack कर दोइसलिए इसे Datalog शैली में
outline-color(Y, black) if data-theme(X, "dark") and parent(X, Y) and data-theme(Y, "light") and focused(Y)की तरह लिखा जा सकता हैयानी
:-कोifसे और comma कोandसे बदलने जैसाइससे आगे जाकर इसे
Y.outline_color := black if X.data-theme == dark and Y.parent == X and Y.data-theme == dark and Y.focusedकी तरह भी लिखा जा सकता है, ताकिattr(X, val)कोX.attr == valजैसी UFCS-जैसी syntax sugar की तरह दिखाया जा सकेअगर इसे और ALGOL परिवार जैसा बनाना हो, तो
forall Y { Y.outline_color := black if Y.data_theme == "dark" and Y.focused and Y.parent.data_theme == "light" }जैसा भी लिखा जा सकता हैयहाँ Y को explicitly introduce किया गया है और एक join को implicit बना दिया गया है, जिससे यह ज़्यादा सामान्य programming जैसा दिखता है, लेकिन असल में Datalog engine dependencies बदलने पर हर बार ऐसे loop को efficiently चलाता है