What Purescript needs

To summarise some of the discussion -

There seems to be little to no disagreement on the following -

  1. We don’t want to dumb down Purescript or compromise Purescript’s language abstractions to increase adoption.
  2. The ecosystem could be better. We need more libraries to cover missing pieces like GraphQL integration, and stuff like libraries, frameworks, tooling, documentations and examples, with a focus on building web related applications (browser and node).
  3. Compiler UX could be more user friendly (better error messages).
  4. We need a killer app for Purescript
  5. Tooling needs to be faster and improve even further. Though no doubt it is already in great shape.
  6. The generated code could be more optimised. However it’s a plus that Purescript generates straightforward code, and we would like to retain that.

The following is more contentious -

  1. Purescript is more mature than its 0.x version seems to indicate.
  2. We want to attract more developers to the Purescript ecosystem. The developers should encompass both people looking for a better Javascript, and people looking for a better FP language.
  3. Some features
  4. Some features required for practical real-world programming are missing in Purescript and may require compiler or language changes. We want to figure out a way forward to incorporate some of them. The best example from this thread is code-splitting / lazy loading.

There is still a conversation to be had about increasing Purescript’s suitability for general purpose use. Some people (like me) would like to see Purescript compete in all aspects with other mainstream FP-ish programming languages. However I’m seeing two lines of thought amongst the naysayers -

  1. Improving Purescript’s Javascript integration is not as important as other things. We should focus on other strengths of Purescript like multiple backends.
  2. Improving Javascript integration is a futile effort because principled strong static typed FP will never be as mainstream as other languages that are either backed by large corporates or cut corners in some ways, and satisfying the demands made by such an integration is not possible to do it without compromising existing features and safety, or the effort to do so is too big.
9 Likes

I think the two are very related. Rust succeeded despite its difficulty because they had working groups solving real problems. The focus on solving problems in specific domains attracts developers, and without developers, you wouldn’t be able to invest in PureScript the Language. Slightly related, the lack of a quasi quoter or something equivalent of template Haskell makes it surprisingly difficult to develop a library that offers a good developer experience for writing GraphQL queries in PureScript. Even JavaScript supports extracting your queries from JS template literals and validating them at build time. If you were solving how to make PureScript an excellent language for web development, then the PureScript language roadmap might change to reflect that.

3 Likes

This is a fun thread.

To me PureScript is the business/get shit done version of Haskell. Anonymous records give me ways to modify complex domain models on the fly that I can’t express in any other typed language I’ve used. I have a proper String type, I don’t need to think about exclamation points on all my data types. Most importantly, I can use libraries that I can trust. Yes, I do trust some Golang/NodeJS/Erlang database connection pool library more than its Haskell equivalent based on very sound preposterofunctor theory. I don’t want to worry about these things, I want a solid DSL for writing my business logic. A lot of people in the Haskell community talk about “Boring Haskell”, I don’t get why they don’t simply use PureScript; probably laziness.
From this point of view, I also think that the many backends are a huge strength and speed in my business layer is not a concern to me. Even if that really matters I can drop into the host language and solve things there. If you want to really tune performance you’re better off doing it in an imperative language anyway.

What PureScript needs in my opinion is people who have fun using and improving it. What does Jazz need? Some crazy innovation, some crossover, mostly great new albums. It probably doesn’t need to sound more like Ariana Grande.

8 Likes

I’ve just decided to give PureScript a try and quite pleased with it. Very nice cleaned-up Haskell, logical and well thought language.

But the moment you actually start doing something here comes all the surprises. While reading the PureScript by Example if you want to actually run tests for exercises they all pass by default. Ok, I go fix it. Then they don’t even run, because they don’t compile. So I have to sit and code all the functions even most obvious ones to just get going. For entire chapter.

But we are just warming up, there’s more to come:

Error found:
in module Test.Main
at test/Main.purs:221:45 - 221:58 (line 221, column 45 - line 221, column 58)

  Could not match type
          
    Record
          
  with type
         
    Maybe
         

while trying to match type { city :: String  
                           , state :: String 
                           , street :: String
                           }                 
  with type Maybe t0
while checking that expression examplePerson
  has type { firstName :: String              
           , homeAddress :: { city :: String  
                            , state :: String 
                            , street :: String
                            }                 
           , lastName :: String               
           , phones :: Array                  
                         { number :: String   
                         , type :: PhoneType  
                         }                    
           }                                  
in value declaration main

where t0 is an unknown type

Random type in error in unknown function (of the ones I wrote), have to go into tests and find where to fix it.

What I expected was I run tests first they all fail saying the function under test is not implemented ( https://hackage.haskell.org/package/base-4.14.1.0/docs/Prelude.html#v:undefined ). Then I fix one it passes, or gives some kind of compile-time stacktrace or other indication where the error is without looking at the deepest point and going up myself. Then you fix them one by one more or less in any order.

Compare it with something like Rails where you get it and in 5 seconds you have app running ready, one more minute and simple CRUD is generated for you, making trying it fun not an academic study. Btw, by CRUD I don’t mean Category-theory Related Universe Discovery :slight_smile:

I believe this immediate result with incrementally building your app attitude is quite crucial for becoming popular, as opposed to investing huge efforts upfront and only then maybe reap some benefits.

1 Like

I don’t agree with this at all. People do care about performance of Purescript programs and I know of cases where Purescript was slowly replaced due to performance issues. And it definitely is possible to do it in Purescript, since Elm, Reason etc. all manage to do quite a good job with performance. I don’t see any reason why Purescript can’t compete with them.

7 Likes

I should have probably clarified this better earlier, however here it is - this thread should not be used to collect grievances against Purescript. If you are facing any issues getting started it’s better to open a separate thread. The purpose of this thread is to collect suggestions of projects the community should work on which would help Purescript be usable in more situations.

4 Likes

I think this is off-topic for this thread, but if you think you have to implement all functions first you’re going about this the wrong way. You should enable tests one by one, not all at the same time.

We actually had a discussion about undefined and it isn’t the recommended way to code in PureScript because you lose all type safety so it isn’t encouraged. We don’t encourage “make it compile and fix run-time errors”, instead we encourage “don’t compile and fix compile errors”.

Using typed holes for this purpose is much stronger than using undefined. Including info on typed holes and how to use them is on the TODO list for the book.

Yeah, it’s definitely slower to get started because you get compile errors, but I think that’s the whole point of this language to begin with. It doesn’t make sense to circumvent that.

6 Likes

I didn’t mean any grief or even more so asked to fix my compiler error messages. That was purely my take to answer the original question. In one word — it needs to get from abstract heavens down to earth at times. Like Elm in error messages, like Rails in bootstrapping initial app structure, and so on.

2 Likes

I want to talk briefly about the Killer App idea.

While I empathize with the desire (and in some cases, need) for better performance, error messages, and JS interop, I think one of PureScript’s strengths, beyond its Haskell-like syntax (not to ignore other improvements over Haskell) is the ability, with relative ease, to target multiple backends.

While the ability to target multiple backends is itself not a killer app, I feel like it may be a fertile ground for thinking of a possible killer app. Especially if another backend is chosen that is itself becoming increasingly popular and much of the PureScript community can get behind as a reasonable language is chosen (personally, think of Rust), then I think the enthusiasm and long-term success of that backend could be increased. It doesn’t have to be Rust, but it seems like a good candidate in some ways (though possibly more difficult to write a backend for than most other languages due to its type system).

Seemless, language-driven RPC seems like it would be the next layer on top of this that would be beneficial, but still not quite a killer app. I think the Rails-like experience described in @ajnsit collection could build on this further and possibly be that killer app.

8 Likes

If I may just talk about what I value in PureScript (as opposed to what PureScript needs), it’s exactly what you’re talking about. The ability to bring an excellent FP language into spheres where no good FP alternatives exist. If I’m doing something with web, I need JS code, but I can use PureScript to produce it. If I’m working on data science or ML, I probably need Python code, but (I think) I can use PureScript to produce it. If I need to build a lot of logic into an embedded system, I need C code, but (I think) I can use PureScript to produce it. (Disclaimer: I’ve only actually worked with the JS backend so far). Maybe the fact that I haven’t actually used other backends besides JS is defeating my own point, but I feel much more comfortable doing ML or embedded work believing that I could use PureScript for the task :wink:

8 Likes

Somewhat unrelated to the exercises comment above, but I’ve been wondering whether I should add exercises to my learning repo that are really basic and focus on things you generally want to know how to do early on in your learning experience. I think I’d make these exercises something only GH sponsors could see. I’m not sure whether it’s worth doing because most people sell books and make the exercises free whereas I’m doing sort of the opposite in this idea.

4 Likes

I think I can most identify with @bbarker with a possible killer feature of multiple back-ends and being able to leverage well-built libraries in language X or converting legacy code Y with ease. I think this is the killer feature for Haxe, but Haxe isn’t very similar to PureScript. I’ve always wanted to touch Purerl (but examples are mostly esoteric), or seeing an FP alternative to Flutter+Dart, or Rust, or Go, or … the list goes on. I find myself running into cool tools and deciding it’s not for me because the language is too lacking in features and it would be monumental to rewrite and maintain a PureScript version. I remember how one of the biggest NodeJS selling points was writing in the same language everywhere, but if the language is more portable than that because it can compile to whatever while still having the features I find hard to live without now. That said, this is a massive undertaking in time and maintenance so if I had to choose one target, JavaScript seems like a pretty obvious choice right now (but could be changing), but I’m not sure what others think about this though.

7 Likes

I don’t use PS myself but am involved in the tech choice. As an outsider and a business owner, my main concerns are:

A) Will we be slowed down by the lack of libraries?

Example: we are using a GraphQL client lib that has caused issues because it’s not mature. How often will that happen? It creates fear which inhibits adoption. I’m happy to have our company invest in the eco by working on OSS, but we’re not FAANG - will we need to invest more than can carry? Will our users suffer bugs and delays that we can’t afford?

Would be eliminated by: Focus on libs that cover common use-cases and then keep growing it. This’ll have a positive spiral effect where more people join to contribute (case in point with our company).

B) Will there be tutorials, blog posts, and videos to help us when we face challenges?

Example: We need to do internationalisation. Is there a recommended way? If not, will we find materials with different POVs or are we on our own?

Would be eliminated by: Generate content, conference talks, examples like realworldapp, and pillar pieces like Halogen. I don’t know PS but I know people love Halogen. That eases my mind.

C) PS is not “boring tech” which has its pros and cons.

Example: will a new developer have a hard time getting into our PS codebase? Elm is limited and may therefore be easier to onboard into. RoR is mature, has strong conventions, and you can expect people to lint with Rubocop.

Would be eliminated by: Does PS have best-practices that the community stands behind? Are they clearly communicated? Are there formatters and linters that people agree on?

Resolving these concerns would have made our adoption decision easier to make, with A being the most important one.

I’m excited about PS and I hope sharing these concerns is helpful. Regrettably, my first post about PS sounds negative, when that’s far from my feelings about it.

15 Likes

Jumping in to the discussion late, but I like what I read. Thanks for bringing this up and moderating it @ajnsit!

I like your words @chrisdone. But I’d like to add that approachability is a big plus. If the only PureScript users would come from Haskell, all would be fine. But for me PureScript finds a sweet spot between Haskell, Elm and OCaml:

  • Haskell/Elm syntax => readable and concise code
  • OCaml/Elm strictness => easier interop with JavaScript and other languages
  • Haskell/OCaml advanced features => better abstractions

All this comes in a neat and comprehansible package: no “which extensions should I enable” (Haskell), or awkward syntax yoga to get async (OCaml ppx). So sorry @ajnsit, but I really like the way PureScript handles things without the need of extensions or plugins. “There should be one or possibly two prefered ways of doing things” keeps the language more clear and comprehensible in my opinon.

Therefore I totally agree with @ntwilson: I think PureScript is the ideal next step for Elm users which are “fed up with Elm’s lack of abstractions” or ReScript users “which want a pure language”. We should accomodate the transition of those developers, instead of focussing on developers comming directly from JavaScript to PureScript. Haskell people will come over any way, when they need a strict variant of what they are used to.

PureScript is already Powerfull and Performant (maybe depending on the backend and there is always room for improvement), and I only wish we’d focus a bit on the Practical aspect. People think higher-order functions and pattern matching are weird: ReScript focusses on that. People think indentation based syntax with juxta position is scary: Elm focusses on that. People think Monads, Applicatives, Monoids, and Rings are scary. Shouldn’t we take a look at that too? A lot of discussions on Reddit/HN/Medium/… are about “Haskellers only think in category theory terms. Use OCaml or F# you you want to get things done!” PureScript the language is already easier than Haskell, why not propagate that in the libraries and the ecosystem too?

For the future (@bbarker, @toastal), I’d really like to compile PureScript to Wasm. I think this is the “killer backend” to work towards. We’d not only be able to talk to JavaScript and the DOM, but also to other languages and use Wasi to build native PureScript apps. We have a huge adventage over Haskell in this aspect, because we’re strict and we’ve already committed to the primitive types Wasm supports. Wasm’s GC support is being prototyped at the moment and tail call suport is in the implementation phase. It’ll take some time to finish, but we can experiment with it in the mean time.

13 Likes

Very strong agree on an eventual wasm backend. I think it’d be a much better investment long-term than optimizing js output.

8 Likes

For me, this is reason enough. All hail WASM.

5 Likes

I agree that specifically optimizing JS output is not a good time investment. I think there is value in static optimizations, but I would really like this to be on an IR that all backends can reuse. CoreFn does not currently fit that need since it can’t express many optimizations done on JS, and JS is too low-level IMO.

6 Likes

I think allowing more programmatic control over the JS output, rather than just optimising it is more important. Being able to interface more easily with JS libraries is a huge win for the ecosystem.

Here’s a wishlist off the top of my head (some of these may be possible with libraries, but they may have other drawbacks and if they don’t then we need to identify and document standard libraries that do this) -

  1. Untagged unions. This is a big one and it would be great to have compiler support for this in general.

    In terms of JS - there are many JS functions that can take a number of different types and distinguish between them based on runtime checks. It would be nice to be able to call them from Purescript seamlessly. I found a library for this that seems good (https://github.com/jvliwanag/purescript-untagged-union) but I am yet to look at it in detail to see if it has any caveats.

  2. Special support for Maybe - Optional values pervade Javascript and I would like to see automatic and zero-overhead translation of Nothing to null and Just a to the unwrapped a in Javascript. There is purescript-nullable but it requires a lot of work to use it (since you have to convert to and from Maybe), and it also breaks referential transparency. IMO Maybe values are important enough to have special support in the codegen for.

  3. Rename functions and record fields. Having a way to annotate an identifier as having a different name in the generated output would make interfacing with some libraries easier. For example -

    type FooBar = {@(as:foo-bar) foobar :: String, ... }
    foo :: FooBar
    foo = {foobar: "baz"}
    

    Would compile to -

    foo = {"foo-bar": "water"}
    
  4. Annotations to use a function as an object method without runtime overhead.

    So this -

    @(method) bar :: Foo -> Int -> Int
    
    bar fooObj 12
    

    Would generate code like -

    fooObj.bar(12)
    
  5. A pie-in-the-sky proposal - Perhaps as a generalisation of 3 and 4, we could have a record view patterns feature, where one can have an FFI object be represented as a record to Purescript without runtime overhead. This would allow all the goodness of row types to be used for arbitrary datatypes. E.g. we could define NonEmptyArrays to have a representation like {head: a, tail: Array a}. Then we could treat it as a record but all calls to arr.head get converted to head arr automatically (again with no runtime overhead beyond the actual call to head itself).

2 Likes

I found option + simple-json helped me a lot in doing some of that funky business JavaScript libraries do. I wouldn’t say the docs are lacking at all, but I really should take some time to write up something that’s very FFI+JavaScript-focused. I was reworking parts of purescript-intl and I think I ended up with something that is type-safe but still feels JavaScript-y (see tests and the configuration record)–which matches the browser API a little better.

I find sometimes blog-form, practical-application of certain tools can be lacking because there’s just not enough time for everyone to do this.

4 Likes

I think allowing more programmatic control over the JS output, rather than just optimising it is more important. Being able to interface more easily with JS libraries is a huge win for the ecosystem.

I think this is only true because PS doesn’t have it’s own developed ecosystem (e.g. stuff like Halogen). In which case optimizing backend (be it JS, WASM or any other) is a huge win cause it means you can do more with PS.

1 Like