-
Notifications
You must be signed in to change notification settings - Fork 0
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
Standards #4
base: main
Are you sure you want to change the base?
Conversation
LANGUAGE pragmata / JustificationThe phrase “signposting”
It’s used in the following contexts:
When you say something needs signposting, do you mean we need to put a comment explaining why we are using it at the use-sites? What do you mean by "signposted" in contrast to "needs signposting"? What do you mean by self-signposting? “self telegraphing”
What is “self telegraphing”? DerivingVia, DerivingStrategies
When you say “ “Since Do you mean in contrast with “.. and is clearly signposted, ..” “ .. while having no effects beyond its use sites, we enable it globally for its usefulness.” Do you mean “we enable it because it’s useful and its effects are limited to its use sites”? NoFieldSelectors
Answered by the Records section of the document. EmptyCase
How does pattern matching on an empty data type work? TypeFamilies, UndecidableInstances
Is this because the optics library needs them? Records
Ah I’ve felt this pain so many times. I think this is why people use some kind of a prefix, like in
Do you mean, we shouldn’t have to rewrite too much code when we split a large record into smaller nested records?
Amen.
Yes! Thanks for recognizing this : )
This will make my life a lot easier, as a beginner to optics. Versioning
Are we going to increment the version number as each PR is merged, or are we going to do that only for the public releases?
|
@itsfarseen - thanks for the feedback! I will address these in turn. Signposting and telegraphing 'Signposting' and 'telegraphing' means 'having to indicate something is going on behind the scenes'. Usually, we use this in the context of 'having to do stuff outside the code to show something is happening'. A class thing requiring signposting by us is For a counter-example, consider newtype Foo = Foo Word64
deriving newtype (Eq, Ord) versus newtype Foo = Foo Word64
deriving (Eq, Ord) via Word64 Here, we see a difference every time it is used. I will rewrite this section to be more clear.
How to use empty data types Empty data types are essentially meant to be 'exciting' as Conor McBride calls them: it should be absolutely impossible to ever have one, and they're often used as 'contradiction proof objects'. However, you cannot, without Why
How we will use PVP version numbers Version numbers will only change for Hackage releases. We'll keep Records When I refer to 'interface stability', the idea here is that a record's representation (how its data is laid out in memory) and its API (how we can manipulate this data by reading and modification) should be kept cleanly separated, such that we can change the representation without having to change the API to go with it. In Haskell 2010, a record's representation is its API: changing the first forces us to also change the second. Optics allow us to separate the two; one of the changes this makes possible, as you noted, is splitting up a record into smaller records. However, it can go much further than this. For example, consider if we wanted to make a type representing ASCII text. Initially, let's say we chose the representation as a pair of data ASCIIText = ASCIIText (Int, [Word8]) We then provided two optics to work with it, which form (a key part of) its API:
Now, suppose later, we realized that our representation was horribly inefficient, and decided to change the representation to newtype AsciiText = AsciiText ByteArray We can keep the exact same optics in place, with the exact same functionality, without anyone having to change anything downstream from us. This is not difficult with optics, but practically impossible with Haskell 2010 records without a lot of work.
The 'let' versus 'where' rules could do with some rewriting. Basically, the problem tends to come up when we have functions being bound to names, rather than non-function values. This is because we can write either this: foo x = let f y = doSomething x y
in f someOtherThing or this: foo x = f someOtherThing
where
f :: ...
f y = doSomething x y However, if we want to re-use a previous -- this works
foo x = let y = doSomething x
f z = doSomeOtherThing y z
in f aRandomOtherThing
-- but this doesn't, because the where can't 'see' y
foo x = let y = doSomething x
in f aRandomOtherThing
where
f :: ...
f z = doSomeOtherThing y z -- y is free here Essentially, the rules boil down to this:
Thus, option 2 from your list is the right interpretation. I'll rewrite this whole section to be clearer. What I meant with the 'type class instances' mention I have no idea, and will remove it. List/String newtypes I think that was a holdover from a previous version that no longer makes sense here. I'll remove it. |
Closes #1. This is the thread for feedback on these.