Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ch8 - Clarify Either e #162

Open
milesfrain opened this issue May 27, 2020 · 13 comments
Open

Ch8 - Clarify Either e #162

milesfrain opened this issue May 27, 2020 · 13 comments

Comments

@milesfrain
Copy link
Member

See #161
There may be an ever earlier appearance to address, and perhaps for a different type constructor too..

@ursi
Copy link

ursi commented Jun 29, 2020

What is the motivation behind making the type variable e? I would have expected something like Either l or Either left.

@milesfrain
Copy link
Member Author

I believe the e is intended to be an abbreviation for "error", which is often what the "left" value is used for, but I agree that abbreviating "left" with l could be better (it just might be confused for a 1)

@razcore-rad
Copy link

Working in making courses and tutorials for gamedev for a while I would say that explicit is better than implicit in 99% of the cases. We ended up doing even trivial stuff like

 for index in range(10):
    # ...

func set_width(value: float) -> void:
    # ...

instead of

for i in range(10):
    # ...

func set_width(val: float) -> void:
    # ...

Why? Because we have to consider beginners that have no coding background as well and it's just easier for them to keep track of what's happening, it's closer to real language and they learn a lot faster through repetition: "oh, if there's a for then it uses some type of index thing".


With that said, all the short versions, Either l, phoneNumber p should be written in full form: Either left, phoneNumber phone etc. in my opinion. You can see they did this in Halogen too, they are using full words for the type variables as it's much simpler to keep track of them for people looking into the docs.

@milesfrain
Copy link
Member Author

Full form could be good (left versus l/e). Not sure if that means we need to update all the other single letter type variables in the book too, and if that will lead to confusion when readers compare these to the other library definitions.

But I feel like the main source of confusion here is in mixing-up Type -> Type -> Type vs Type -> Type. See #160 (comment)

@milesfrain milesfrain changed the title Clarify Either e Ch8 - Clarify Either e Nov 22, 2020
@razcore-rad
Copy link

Well two things:

  1. Yes, I'm talking about using long-form variable names in all cases, not just this Either case, so all book. It's just demonstrably better for beginners to follow along
  2. The confusion with type application is definitely a big part too. In ML languages we have this ability to program in the type system and I think this isn't made clear enough for people that come from OO, I know I had trouble understanding this at first. Also the terminology doesn't help much. We talk about values, types and kinds, but there's mixtures like "type variables" whereas the traditional programmer would immediately think of "value variables" because that's what he know "variable" to be in the first case.

There's a lot that people coming from other imperative languages are going to miss on a first pass. It might even be a good idea to have a subchapter somewhere discussing terminology. Like class is another one of the problematic ones.

@milesfrain
Copy link
Member Author

1. using long-form variable names in all cases

Ch7 is pretty heavy with single-letter variable names, so I think this would be a good place to experiment with the feasibility of longer names and decide on a policy of where we draw the line on when to go longform. Do you want to make a PR for Ch7 with the proposal you have in mind?

For example, do we expand the type variables of our custom combineList, and then do we expand them in the existing sequence?:

combineList :: forall f a. Applicative f => List (f a) -> f (List a)
sequence :: forall a m. Applicative m => t (m a) -> m (t a)

There's a lot that people coming from other imperative languages are going to miss on a first pass. It might even be a good idea to have a subchapter somewhere discussing terminology. Like class is another one of the problematic ones.

We can certainly do more to cater to folks coming from specific languages. I'd like to make comparisons (and cheatsheets) for other languages purescript/documentation#334. The book's intro would be a good place to link to the comparisons (discussed in #173). Contrasting OOP involves more work, so I'm thinking we can leverage existing Haskell content - posted some ideas for that in purescript/documentation#334 (comment).

@hdgarrood
Copy link

Yes, I'm talking about using long-form variable names in all cases, not just this Either case, so all book. It's just demonstrably better for beginners to follow along

I don't agree with this at all, actually. I think combineList and sequence are perfect examples of this. These functions are general enough that there is no single word you could replace the type variables with which wouldn't be overly specific; at best, you'd be giving the impression that the function is not as general as it actually is, and at worst it would be actively misleading. What we really need to do is to equip beginners to ingest the information which is already present in the type signature.

@razcore-rad
Copy link

Yeah, I have to think a bit more about this cause when comparing with functions from libraries doesn't seem like it's a good idea to use full-words, didn't think about it at the time.

@JordanMartinez
Copy link

What we really need to do is to equip beginners to ingest the information which is already present in the type signature.

☝️

@razcore-rad
Copy link

I think you guys have the misconception that using full-words instead of symbols is antithetical to teaching beginners the basics. The idea is to make a smother transition.

I've been thinking about this a bit and given the above example I'd do something like:

combineList :: forall any applicative  .                  Applicative applicative => List (applicative any) -> applicative (List any)
sequence    :: forall a   m           t. Traversable t => Applicative m           => t    (m           a  ) -> m           (t    a  )

That's to say we keep the symbolic form of the library functions, but whatever we write as explanations/exercises we use full-words. When I get a chance I'll make a PR to see it in practice and see if we can agree on something.

@hdgarrood
Copy link

I understand where you’re coming from, I just don’t agree. Using full words for type variables encourages the reader to derive meaning from those type variables, when really they should be looking at everything else in the type signature except the type variable names. As for that specific example, any is dangerous as it means something very different in some other type systems like TypeScript’s.

@razcore-rad
Copy link

razcore-rad commented Nov 27, 2020

Yeah, I know what you mean, I guess we probably just disagree about this, let's see what the others have to say.

As for any being dangerous, I don't think it's any more dangerous than class meaning something completely different in FP vs. OOP so I don't think that alone is a compelling reason to not use it, but I'm open to other suggestions.

@razcore-rad
Copy link

So I've been thinking lately about this and looked at ch7. The complication with long-form type variables is that a lot of examples from Prelude and other libraries use short-form variables and I don't think we can get around this so I'm dropping the idea of long-form. I guess FP is just special that way :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

No branches or pull requests

5 participants