I'm really starting to convince myself that Haskell is the ideal language to implement CSS in.

The biggest challenge in Rust was in defining the CSS properties, for which I implemented my own DSL. librsvg has a simplistic implementation that suits them fine, and the other browsers rely at least partially on their own DSLs.

But Haskell's pattern matching and laziness would provide a near ideal DSL out of the box!

And it's currying syntax makes for a great parsing and interpretation syntax.

@alcinnz not knowing how css is implemented, could you showcase some simpel examples of how haskell is making this easy/more natural? What kind of common patterns do you need to solve?

@rune I'm just starting to verify my theory, but a CSS engine typically consists of the following steps:

1. Lex then parse the stylesheets.
2. Expand shorthands and, so it syntax errors don't interfer with cascade, verify property syntax.
3. Look up selectors that potentially each element.
4. Interpret those selectors over the element.
5. Sort the style rules and evaluate cascade.
6. Translate into a more optimal memory representation whilst applying inheritance.

1/2

@rune The most important thing is for it to be trivial to define new CSS properties because there's a lot of them. Let's say there's a single function for parsing them.

Haskell's pattern matching syntax helps here because then we can define new CSS properties with a new pattern for that property parsing function. And Haskell's laziness with seperating syntax checking from parsing.

Though more generally seems like a good choice for implementing languages due to it's currying.

2/3

@rune To make this more concrete I'm salivating at the concept of defining new CSS properties being as simple as writing:

prop _parent style "background-color" Url(value) =
Just backgroundColor style value

This is better than what other browser engines get by compiling their own DSLs!

I'm not sure I'm explaining myself well...

@alcinnz fascinating! So you essentially get to define a row of simple functions that are curried together to parse the properties?

Would you do all the above steps in one curried function chain or is there a logical division such as first lexing it out into selector groups and then parsing each property to preserve simplicity?

Does that allow for parallazation since each group doesn't interact until you need to compute their effects?

@rune Ofcourse you could.

And interestingly it's a common optimization to split the underlying storage up into chunks like that, as it reduces how much memory needs to be allocated and copied around. Haskell would enforce the mutability rules for me, but usually refcounting is used.

Follow

@alcinnz nice :)

Giving me flashbacks to functional programming class in university. I don't miss everything from that time but a lot of the stuff taught there was really interesting.

Sign in to participate in the conversation
Librem Social

Librem Social is an opt-in public network. Messages are shared under Creative Commons BY-SA 4.0 license terms. Policy.

Stay safe. Please abide by our code of conduct.

(Source code)

image/svg+xml Librem Chat image/svg+xml