How to learn PureScript in 2020?

@cheery, If I was starting out with the language, I’d feel more confused after reading your explanation.

I think beginners need concrete examples. Elm does a really great job with these introductory materials. Here’s Elm’s coverage of Maybe:

Here’s what we have, which isn’t nearly as accessible:

Should we strive to match Elm’s thoroughness? This will be difficult for PureScript because it’s a bigger language with a lot more stuff to document.

@Ding, You may have a less frustrating learning experience if you start out with Elm to master the basics of functional programming, and then transition to PureScript once you’re ready for more language features. Pretty much everything you’ll learn in Elm applies directly to PureScript, and the syntax is really similar.

I’m curious, how did you discover PureScript and what led you to selecting it over the many other alt-JS languages?

2 Likes

Could you clarify what went through your mind when you saw that link, whether via the Book’s reference to it or the Documentation repo’s reference to it?

I’m wondering if the title of the repo itself is misleading.

Why did you think it’s not very active? It’s actually pretty active, and there’s a high chance you will get an answer. (Speaking from experience here.)

It’s fine if you don’t like Slack; however, I don’t want you not using it only because it seemed not very active because really, it’s the opposite.

3 Likes

@mhmdanas
I was using the standard of an active instant messaging group to match slack channel :grimacing:

@JordanMartinez
The title of the repo make me thought it was something belongs to advanced learners, if someone need to figure out something under the hood they should try to read the “reference”.

When I saw the readme.md , the table of content looks overwhelming. Actually I feel it would be better to exchange the “table of content bold and not bold version” with the first section of “table of content detailed version”. Keep it simple at first glance.

Above are my personal experience feedback :grin:

@milesfrain
Actually I was started with Elm… I was amazed by their useful error information and “undefined is not a function will never happen”. Then I feel like it’s a little bit too restricted, and then I read this looooong article , PureScript was mentioned multiple times in the comments area. Many people saying that PureScript is a good choice but yet has comprehensive ecosystem. Thus I chose PureScript :smile:

@cheery
Thanks for your detailed explanation but it’s too difficult for me :persevere: I’m still confused by many basic syntax. When I see a block of PureScript, the first question come to my mind is: how to distinguish which one is a type, which one is a variable? I don’t know. And it seems that type is using along with variable everywhere, in TypeScript usually I’ll use colon “:” to tell the former is usually a variable and the later is usually a type,

a: b
c: d

but in PureScript:

a b
c d

I’m… :sob:

I still have a lot to learn. nothing, just, forall, functor, thin arrow, fat arrow, double colon, the period… I still have a lot to learn.

5 Likes

Thanks for the feedback!

The overwhelming nature of the ToC is a bit of the reason why learning FP languages are hard. There’s just a LOT going on. I experienced too many times where not understanding some foundational concept bit me later when I was working with more complicated libraries. So, my repo tries to be as clear and concise as possible while still explaining all one should need to know.

The detailed ToC exist so one could easily jump to any part in the repo. I guess it’s my temporarily solution to the problem of navigation in that repo. I wasn’t sure how many levels deep the ToC should be. Too few and it’s just an overview without allowing you to skim it. Too many and its overwhelming.

Also, I can see why the name would be understood that way. In some ways, the name is fitting and in others it is not. It’s definitely not a “quick-start” guide to PureScript. It’s more like an “in-depth” beginner’s guide to PureScript, so one is less likely to be confused later.

3 Likes

@Ding Well, let’s start with basics then. The stuff you’ve told so far is really interesting. I believe you when you say that it’s difficult to you. Just don’t worry that you would not be smart enough, I think you are. You can see everybody agrees the documentation needs work, and you partially know a lot of this if you’ve learned Elm. If we discuss here about the difficult things, it can be used to improve the documentation and that helps the community to grow.

If we start from the basics, we got type declarations just like in the language you’re coming from. Elm uses a single colon on type declarations. Purescript uses double colon. I think the preferred custom would be use of the single colon because types are important. Though Purescript ended up retrieving this feature from Haskell that uses the single colon differently. Either way it’s ok I guess.

In purescript, you’d be writing:

a :: b
c :: d

Type, b and d in this example, could be thought of as terms that determine how other terms, a and c, should be interpreted.

The game semantic interpretation may be useful here. Types in Purescript can be interpreted as games. Type describes what kind of game you play, and the definition is a strategy that never loses that game.

Now I think this should be checked whether it’s correct. I think that the idea of “not losing” allows you to define strategies that repeat infinitely many times and do everything to stop the game from progressing. The traditional way to explain the interpretation is to say that the definition is a strategy that always wins the game. However it’d be a non-turing-complete language that we’d be describing if you had to always win instead of preventing that you ever lose.

  1. If we got something like (Unit), it’s a game where you always win. You don’t need to do anything and you can answer with the (unit). That is, unit is a valid play to Unit, and this may be claimed by writing unit :: Unit.

You can follow this in try.purescript.org, If you like to do that, write in the following to give it a try:

a :: Unit
a = unit
  1. If you got (Void), you can’t win. The opponent has (absurd) to defeat you every time. This is useful to know because the sides may switch.

  2. forall a. b is a game where the opponent can select the game a and it gets substituted into the game b. You are required to provide a strategy to not lose in any of games that opponent might construct by replacing a with any type.

  3. The arrow (a -> b) means for a game where you retrieve a variable to initiate the game (a) with the opponent as many times as you want. You can use those plays to win in the game (b).

In the arrow-game, the opponent must supply a game (a) to obtain a play to the game (b). The game is supplied with the “apply” -syntax. Eg. If the (f)is valid play to (a -> b), and (x) is valid play to (a), then (f x) is valid play to (b).

Examples, here’s the “forall” and arrow together because they appear together a lot. The examples are examples of copycat strategies, you take an opponent’s play, and repeat it against himself:

c :: forall a. a -> a
c x = x

d :: forall a b. a -> b -> a
d x y = x

Also the game where the opponent can’t win may be interesting:

e :: forall a. Void -> a
e x = absurd x
  1. The record is a game where opponent may challenge you to play multiple games and you have to win them all. {x :: a, y :: b, z :: c} means you got games a, b and c. The opponent may select the game a with the label .x, and so on.

Below’s an example of a game where opponent is challenged to multiple games with you, here’s also something crucial you already saw earlier. You put the opponent to play against himself and he can’t do anything else but to lose.

h :: forall a b c. {x :: a, y :: b, z :: c} -> b
h record = record.y

Likewise to play such games, you got the record syntax to combine plays:

i :: {x :: Unit, y :: Int}
i = {x: unit, y: 4}

Now, if you understand this, next we can proceed for explanation of the Functor and the fat arrow (=>). We should verify that you understand these things before proceeding there though.

As an exercise, you could try to look at the lines starting with :: and see how far you get. Can you explain what kind of games they represent?

An another exercise, describe an always winning strategy for this game (this means same as giving it a definition that passes a type checker and can be guaranteed to terminate):

s :: forall a b c. (a -> b -> c) -> (a -> b) -> a -> c

Some additional help to building terms in try.purescript.org: If you do this:

s = ?hoo

You get a different error that looks like this:

Hole 'hoo' has the inferred type

  (a0 -> b1 -> c2) -> (a0 -> b1) -> a0 -> c2

Now you can start progressing with the solution:

s x = ?hoo

And you again get a different error:

Hole 'hoo' has the inferred type

  (a0 -> b1) -> a0 -> c2

in the following context:

  x :: a0 -> b1 -> c2

It’s very much like playing some sort of a game.

If you feel something needs further explanation, or it still needs to be simpler, please let me know. I’ll supply with all you need to understand this way to understand Purescript. Also if you feel like it’s a bit silly, well… This is not something I came up with. I learned this and have found this useful, but I may not know how to express how it is useful.

Update: I think it’s about semantics. There is a bunch of PDF slides that say game semantics are a form of denotational semantics. Types have multiple semantics and those can be used to understand what types mean.

Also, how do everybody else think about this? Would this be a good approach to explaining Purescript? I think this is being used to explain formal logic, and I think it does also work here. Or have I mixed it up more?

1 Like

I might be biased because I already know get how Types work. However, if I was a new learner to PureScript, this explanation would have been hard for me to follow, mainly because of the “game” theme. I can see how using typed holes can feel like playing a game, but I don’t think that analogy is sound. Games can be played casually where the end-user is just wasting time and actually doesn’t care whether they win or not. Types are more like logic: X is inferred to be true because Y is true.

My current understanding of Types is that they represent a Set of values. For example, the type Boolean has two possible values: true and false. If I have a function, Boolean -> Boolean, it tells me two things:

  1. Only two possible values can be passed into that function
  2. Only two possible values can be outputted by that function.

As a result, I have a pretty good idea as to what this function does. It’s either not, where the argument is inverted, or identity, where the argument is outputted.

not :: Boolean -> Boolean
not true = false
not false = true

identity :: Boolean -> Boolean
identity theArgIsTheOutput = theArgIsTheOutput
4 Likes

In TypeScript, you annotate a value with the type to the right of it using a single colon:

valueName: Type = 4

In PureScript, you annotate a value with a type above it using two colons:

valueName :: Type
valueName = 4

Without the type annotation, PureScript looks like most other language:

valueName = 4

However, PureScript and Haskell emphasize types. Rather than writing something like this in Scala

// not sure whether this syntax is even correct
foo[F[_], A](arg: A, fa: F[A]) { 
  .. body .. 
};

We can separate the value-level code (i.e. where values and functions are implemented) from the type-level code (i.e what the corresponding type of the value is):

foo :: forall f a. a -> f a -> output
foo = -- body

This tends to make it easier to read the code when types get complicated.

3 Likes

I see each type as a set of values as you do but, just to clarify, your hypothetic function could be

constTrue :: Boolean -> Boolean
constTrue _ = true

or

constFalse :: Boolean -> Boolean
constFalse _ = false

also.

1 Like

Here’s something fun. That is, you don’t need to know this, however it’s a fancy trick. How do you know that you’ve exhausted the possibilities of implementing some functions? You can use algebraic types for this.

You’ll see (Boolean -> Boolean) is 2^2 in algebraic type notation. This means there should be 4 possible ways to implement the function, plus getting stuck. Also, the type is isomorphic with 2*2. The * stands for product. That is we get the following truth table that tells the 4 possible way to implement our function.

This output          is produced by this function 
vvvvv vvvvv          vvvvvvvvvvv
false false     <==> const false
true  false     <==> not
false true      <==> identity
true  true      <==> const true

This table contains the functions mentioned by @JordanMartinez and @Ebmtranceboy.

2 Likes

Btw. I’m a bit frustrated about this. I appreciate this feedback but it took me a good while to understand how useful the things I’ve told about are and you’re outright rejecting it in this context.

I think you’re not reading my posts and I find that a bit rude. Sure I did not mention there’s a whole Wikipedia page on game semantics. If you read it you’ll find out there are amazing things that has been done with this approach. I would think it is an approachable way to teach semantics of functional programming languages, since they are closely related to formal logic. I even attempted to address the differences.

Now if we look at Elm. I acknowledge they’ve done pretty neat things there too. I really think their getting started documentation is brilliant. I love the interactive prompts that allow you immediately try out things while you read. I think that also worked on mobile. However, I am pissed about the unwillingness to address difficult things with fear that they’re alienating the audience by being too difficult to understand. That’s likely an one reason they dropped type classes despite how useful they are. If something’s useful then we’ll do best if we find out a good way to teach it.

Indeed, it is moreover quite conventional to note R to the power D the set of functions from D to R which has at least the advantage to remind that the number of such functions is #R to the power #D.

1 Like

I think the game perspective can definitely be useful in some contexts, but in this particular case it’s pretty clear to me that it’s not appropriate. In particular, the OP has explicitly mentioned the kinds of resources they are interested in, and the things you’ve linked to are pretty much diametrically opposed to it in their approach. I don’t doubt your good intentions but I do think it does more harm than good to link to things like the Wikipedia page for type theory and a video of Wadler discussing the Curry-Howard isomorphism in response to queries like “I would like to be walked through building a web app step by step”; we’re trying to dispel the myth that Haskell and PureScript require a PhD in mathematics, not reinforce it.

7 Likes

All right, I think I see that in the first post now. I totally zoned out after reading he needs help with understanding what is a type. I’m sorry about that.

3 Likes

Ha! My bad! Thanks for pointing out that mistake on my part.

no problem. It’s true that doesn’t seem to mean much, but exhaustivity can make things easy to grasp for some beginners. For instance, prove the difference between

Maybe Boolean -> Maybe Boolean -> Maybe Boolean

which is

Maybe Boolean -> (Maybe Boolean -> Maybe Boolean)

and

(Maybe Boolean --> Maybe Boolean) -> Maybe Boolean

just by showing that the first type has 19683 inhabitants whereas the second has much much more !

PurseScript is based on Haskell. I’ve been reading “Get Programming with Haskell”. Now things are making sense when I look at PureScript

4 Likes

Here’s a video walkthrough on how to get started with the book, including how to grab all required dependencies, setup an IDE, and run the chapter tests. Hoping this lowers the barrier to entry.


Would this video be useful to include at the beginning of the getting started section? Any cleanup suggestions?
7 Likes

I also tag-teamed between the PureScript book and Learn you a Haskell when learning PureScript. Oftentimes when something in the PureScript book didn’t make sense right away, the description of the same concept in Learn you a Haskell would be more approachable.
I love the PureScript book as a general resource, but I think Learn you a Haskell is more targeted towards an audience that’s learning FP at the same time as learning the language. I bet there are some good Elm resources you could say the same thing about, though I don’t know much about Elm…

3 Likes

We could make a clone of LYAH and do some minor edits to the text and examples to make it target PureScript. The license allows creating derivatives. Would this be a useful resource?

Here’s a quick starting point with the intro rewritten as a proof-of-concept.
https://lya.ps.ai/
See this strategy discussion in the repo for planning next steps.

3 Likes