96 karma · joined November 12, 2014
https://medium.com/fuzzy-sharp/migrating-to-postgres-2dc1519...
TL;DR: persistent + esqueleto + servant
Now consider categories with various types of constructions (products, limits, exponentials, etc.) and you'll notice they correspond to requiring certain features in your language.
impact :: Web -> Web
Persistent data structures will let us reuse the best parts of the old web efficiently.Now I'm curious :)
http://try.purescript.org/?gist=63d81adf9f5257ffa4f576df2658...
The representation is fairly compact, so the requirements for a PureScript compiler backend are fairly minimal. You just have to translate all of the features of the IR:
- Functions with lexical scoping - Support for the primitive types defined by PureScript (we need to define some of these types more concretely in a specification) - A way to encode records. This could be something like JavaScript's objects, or just a map data structure.
The JS backend actually does more optimizations before code generation, but it starts from the same intermediate representation.
[1] https://github.com/paf31/24-days-of-purescript-2016/blob/mas...
In some of the standard libraries, yes, that's true. However, it's possible to use PureScript without the standard libraries, and use alternatives such as Preface (a teaching library) or Neon (an alternative to Prelude)
https://github.com/paf31/purescript-preface
http://pursuit.purescript.org/packages/purescript-neon/0.1.1
npm install -g pulp purescript
should be enough now.
I think part of the problem is that type classes are so easy to abuse. When you have a problem like e.g. monad transformers, where a) you have a lot of boilerplate code which would be irksome if written out by hand, b) you have laws to make sure the generated code is sensible, and c) your types have exactly one such sensible instance, then classes are very nice. Abuses of type classes exist where any of the three above conditions fail to hold IMO, and a scrap-your-typeclasses approach can be very valuable then.
I will say that the types in Halogen seem more complex, but they can be justified by the fact that the coproduct machinery helps ensure all actions get handled somewhere. This may be possible with prisms, I'm not sure yet. This library [3] seems relevant.
One issue I've found, which I understand the Halogen folks are also finding, is that it is tricky to wire up action handlers such that a subcomponent can invoke an action and have a parent act on it and invoke its own action in response. Granted, this is a relatively infrequent use case, and you can always push such logic into some shared parent.
[1]: https://github.com/paf31/purescript-thermite/ [2]: https://github.com/zrho/purescript-optic-ui [3]: https://github.com/joneshf/purescript-totally
[1] http://package.elm-lang.org/packages/evancz/focus/1.0.1/Focu...
Now though, Elm has become a more general-purpose language, adding effects and various other features, and PureScript has better UI libraries and tooling/editor support. So the gap has closed somewhat.
Speaking generally, the goals of the two projects are pretty similar. I can't speak for the Elm community, but "bring strongly-typed FP to the JavaScript community via the web platform" seems to approximate the goals of both projects pretty well (maybe someone from the Elm side can correct me here?) So the goals are similar, but the execution is very different. I think Elm and PureScript differ greatly in opinions regarding _how_ to bring strongly-typed FP to JavaScript. This is not just a question of language features (type classes and HKTs are often mentioned), but also things like how the language should present its foreign function interface to JavaScript, what the entry point to an application should look like, whether to build features into the language or in libraries, how to grow a language community, etc. In practice, these make the experience of using each language very different.
> when would we want one vs. the other?
Elm provides tools with which you can become productive quickly. Also, it's used in production by NoRedInk and others, so it's clear that it is general-purpose enough to be used for real applications. I think there will be two paths to PureScript for most users - from Haskell, and from JavaScript, quite possibly via Elm. Just as users might move to Elm because they want type safety and expressiveness, they might move to PureScript because they find themselves wanting even more type safety and expressiveness. Certain abstractions are possible in PureScript, but (I think, again, would be glad to be corrected..) not in Elm - free monads, monad transformers, monadic tail calls, van Laarhoven lenses, etc. SlamData is an example of an (open source) company putting these tools to great use.
All three of those have very different goals and trade-offs from GHCJS.
I agree that it would be nice to share more work/knowledge though. One of the nice things about AltJS is that several languages can coexist in the same codebase.
[0] slamdata.com
[1] github.com/bitc/purescript/tree/psc-compile/psc-compileSome effects in PureScript look a lot like the effects provided by certain monad transformers (StateT/ST/Ref, ExceptT/Exception, etc.), but there are differences in terms of how things compose. Take StateT and ExceptT for example: you can compose them in two ways, and get two different monad transformer stacks, with different behaviors (surrounding how state propagates when an exception occurs). There are valid use cases for each, but with the ST and Exception effects, there is only one way to combine them: the way the underlying (Javascript) runtimes chooses for us.
There are things which each one can do which the other cannot. Fortunately, we can mix and match in PureScript since we have the purescript-transformers library. A typical arrangement is to stick Eff on the bottom of a monad transformer stack.
_Edit_: of course, everything you can do with a monad transformer can be done more verbosely with pure functions and the underlying monad, so you _could_ replace monad transformers with Eff in many cases, but in practical terms, it might not be all that useable in some cases.
Concretely, if you think about promises in JavaScript, for example, if you have a function A -> B -> C -> D, say, and you have three promises of types Promise A, Promise B and Promise C, you can construct a Promise of type Promise D by running the three in parallel, and applying your three-argument function when they are all done. So you've turned a function of type A -> B -> C -> D into one of type Promise A -> Promise B -> Promise C -> Promise D. If you can do that sensibly for any number of function arguments, you have an Applicative. ("sensibly" here means that there are type class laws which have to hold)
Every Monad is also an Applicative functor, since you could use do notation to compose your promises instead, but there are other interesting Applicatives which do not come from Monads.