JSX syntax and QuasiQuoters in PureScript

It would be nice to use JSX syntax within PureScript. I do not know to what extent this is easy or not to implement and desirable.

I have seen these projects that could serve as references, both abandoned:

A JSX to Elm compiler

https://github.com/pzavolinsky/elmx

A JSX parser for Reflex (Haskell)

https://github.com/dackerman/reflex-jsx

The latter uses quasiquoters.

Would it be useful to have QuasiQuoters in PureScript?
@paf31 proposed 5 years ago: hxxps://github.com/purescript/purescript/issues/1643

The idea of QuasiQuoters and custom DSL is very seductive but gives the impression that it has not seen much use in Haskell.

What is your opinion?

3 Likes

I might be misreading, but I think that proposal is for there to be support for purescript quasi-quotes in the compilers implementation, not in purescript code?

I think what you’re asking for is meta-programming of Template Haskells strength (although not necessarily the same approach): Template PureScript?

I’m personally not too bothered about not using a JSX/HTML syntax directly in the code, although it would be nice

2 Likes

@jy14898 surely I misunderstood @paf31’s proposal

I have done some research on the subject and have also tried to implement some ideas of how to allow JSX syntax together with PureScript code in the same file but using a different extension, for example .pursx. For this you need a custom parser and for development a custom language-server

All of that seems quite complicated. At the end of the day it is very easy to combine PureScript code and Javascript files in the same project. There is not much to be gained by combining the two syntaxes.

I answer to myself :slight_smile:

I think the Hamlet library in Haskell may also be useful as a reference: https://www.yesodweb.com/book/shakespearean-templates

This is my view as well. It’s of course unfortunate that you don’t get the same level of type safety if your templates are written in JS rather than PureScript, and I think not being required to switch to a different file to edit your templates would be an improvement, but I think the amount of effort to get some kind of macro system going in PureScript in order to support JSX is just very difficult to justify compared to other things we could be doing.

4 Likes

Very interesting the link of Hamlet, Thanks for sharing

Yes, better to use the few human resources that PureScript has in other better things than trying to make JSX more typesafe.

I think the “best” solution is to have an ESLint mom telling you “kid don’t do that” :slight_smile:
I found these rules that “force” you to write more functional code in TypeScript

@hdgarrood you know a “better” approach?

Personally, I have a bias towards writing templates in the host language (so in this case, PureScript). That way you get to use all of PureScript’s nice features for things like iterating over collections, extracting reusable code into functions, (all the things that templating languages tend not to be so good at), and you get type safety, all the editor tooling still works, etc etc. So that would be my recommendation unless there’s some context which makes that unworkable, such as your templates needing to be maintained by designers who don’t know PureScript.

I haven’t written enough JavaScript/TypeScript recently to be able to comment much on the approach of using lint rules like that. It does at least seem worth a try, but you’ll need to tell TypeScript what the types of the data you’re passing to your templates are if you want to benefit from its type checking, and I’m not sure how easy that will be.

5 Likes

A QuasiQuotter would open up many use cases that are currently hard to do in PureScript. GraphQL and SQL query validation are the two biggest ones that are not discussed in this thread.

2 Likes

I’d like to suggest that the reason why JavaScript needs JSX (or TSX) is that it’s hard to declare DOM trees in JavaScript, and that reveals the weakness of JavaScript, not the power of JSX.

I think almost every external domain-specific language reveals the failure of the host language. Lately I’ve been translating a lot of TSX into PureScript React Basic Hooks and I find that the translation goes pretty much one-to-one line by line. Each line of TSX can be translated into an equivalent line of PureScript, with about the same amount of syntax. For the problem domain of declaring DOM trees, the expressive power of general-purpose PureScript is about equal to the expressive power of domain-specific TSX.

We don’t need a special domain-specific DOM tree declaration language in PureScript, because we already have PureScript. And that’s great, because not needing a DSL to express what we want to express means we also don’t need extra special DSL toolchains and IDE support and a whole new syntax to learn.

7 Likes

Let me spam with this snippet once again here - maybe someone will find it useful. We use this a bit inefficient syntax (but I count this as a pretty efficient “DSL” ;-)) when writing react-basic JSX and it allows us to have clearer tree structure because children array ends up outside of the props record:

jsx = div $ { children: _, classNames: "class-8" }
  [ div $ { children: _, classNames: "class-9" }
     [ ...
     ]
  , div $ ...
     [
     ]
  ]
8 Likes

I don’t follow how declaring DOM trees is harder in pure JS/TS than PureScript. For example, react-basic in PureScript:

R.button
  { onClick: capture_ $ self.setState \s -> s { counter = s.counter + 1 }
  , children: [ R.text (self.props.label <> ": " <> show self.state.counter) ]
  }

vs

pure JS/TS:

h(
  "button",
  { onClick: () => this.setState({ counter: this.state.counter + 1 }) },
  this.props.label,
  ": ",
  this.state.counter
);

I don’t see much difference here.

1 Like

@jamesbrock

I think almost every external domain-specific language reveals the failure of the host language.

As we know, eDSL are dialects created specifically to declare (declaratives) or specify (imperative) the domain of a concrete problem following the principles: simple, expressive and concise. In my opinion it is not possible to develop a general language that covers all domains and at the same time complies with the three principles. The limitation or failure is in the capacity that the current average human being would have to understand it.

That being said, PureScript is a great language that follows all three of the above principles and integrates quite well with other DSLs, like JSX.

@utkarshkukreti

I don’t follow how declaring DOM trees is harder in pure JS / TS than PureScript. For example, react-basic in PureScript:

PureScript for web development is not the problem if you are a Fullstack developer. But it is not a viable syntax for designers and frontend specialists used to syntax derived from HTML.

<button onClick = {() => updateCounter (s => s + 1)}>
  {label}: {counter}
</button>

This snippet is understood by anyone with a minimal base of HTML.

2 Likes

I think you’re in agreement with me. I was addressing this statement by jamesbrock:

by saying you can write DOM using functions in JS exactly like PureScript.


Agreed and that is what I prefer (and use) as well.