Can Haskell’s deriving mechanism be simplified? Cody Goodman, Cameron Gera, and Taylor Fausak walk through the changes that Matt Parsons suggested.
Episode 31 was published on 2020-11-16.
>> Hello and welcome to the Haskell Weekly podcast. I'm your host, Taylor Fausak. I'm the lead engineer at ITProTV.
>> And I'm Cameron, another engineer here at ITProTV. And I just was going to say thank you to all those who filled out the Haskell survey. We will be looking for those results here in the next couple weeks. But we're just glad that we could get your participation and hear what you have to say and your feelings and thoughts about Haskell as a whole. So thank you. Thank you, Thank you. I really appreciate it. And I know Taylor does as well.
>> I'm Cody Goodman, another engineer here at ITProTV. and looking forward to talking about simplifying deriving today.
>> Yeah. So this blog post by Matt Parsons came out a couple days ago, and it proposes, I think, in the tweet where he first announced it. He said terrible ideas worth discussing. So here we are, discussing them.
>> Ooh, there's three people. This is exciting. Yeah. I mean, uh, as probably the least experienced Haskeller here, I will start with my two cents. Uh, I think it was a good article at the end of it. I was like, Okay, yeah, I could get behind this because I think, you know, when I started Haskell, I didn't really understand that there were different types of deriving. Um, you know, really, Until we talked about it, you know, even a couple of episodes on the podcast ago about the various types of deriving. And, you know, I think there's a lot of boilerplate that, you know, he iterates through in this podcast and in this blog post that, you know, I'm like, Oh, like it's just kind of eye opening. So, you know, I'm really, you know, excited to dive a little bit more about this. Um,
>> yeah, you mentioned, uh, a few episodes ago. We talked about that post by Kowainik that really dug into all the different types of deriving and what they do and when you might want to use them. And this post, in a way, is kind of the opposite of that. Where it's suggesting, let's get rid of all those differences and have fewer things that kind of work or can have the same effect.
>> Yeah, I do like how How do you How do you pronounce that Kowainik
>> Kowainik is how I say it. I'm not sure if that's right.
>> Kowainik. Okay, uh, I like how they wanted to make everything explicit. That be cool is like some HLint rules or something. It was like a stopgap until something could potentially simplify deriving. Because I think there's a lot of potential there.
>> Yeah, and, uh, let's let's get right into what it would mean to simplify deriving. So the very first thing that he suggests, I hope, is something that everybody can get behind, which is adding to the list of stock deriving classes. Because right now, with no extensions at all, there's only a handful of things that you could derive like Eq Show Read Ix, I think popular one.
>> I mean, I use it every day, I don't know what you're talking about.
>> And there's a bunch of extensions that just turn on like one extra class that you can derive like Functor, foldable, traversable, that kind of stuff. And it's weird that these aren't included, and I think really the only reason I can think of is that there hasn't been a new version of the language report to include this stuff in?
>> Yeah, because I mean, these things are in most Haskell packages are probably already enabled so I would, you know, think. Yeah, let's just put these into the stock deriving strategy. And I know we kind of talked about this, actually. Last podcast, I think where we said, you know, hey, let's get this group of, uh actually, it was two podcasts ago. to this group of language extensions and just say, Hey, here's this one language extensions that includes all of these other ones. And I think that was kind of, you know, Yeah, I don't think that would be necessary if we could just you say All right, you know, stock derive all these pretty normal classes.
>> Yeah, I think the core library committee was, uh, since it's so hard to get a new report out, I think they were trying to say what language extensions. They wanted to be the default. Asking the community about that. I think this would be a good candidate for it. Things like derive functor foldable traversable.
>> Yeah, pretty much derive star like any of them, except except derive any class. So it's funny. We want to derive. A lot of individual classes, but not any class. And he claims it's a foot gun. Uh, I didn't immediately know why. Do one of y'all know why?
>> Yeah, I've been bit by before. If, uh, if you want to derive something Ah, and it's not stock. derivable You're probably gonna see derive any classes as a suggestion, and then you're going to run it, and you're gonna get a a runtime error. Hopefully not in production. And it is definitely a foot gun.
>> Oof! Runtime errors are no good.
>> Mhm. I need to get, like, a little, uh, sound effects. Yeah, Yeah, Something I'm sure I'm sure the production team at ITPro has something for me. I'm gonna talk to him for next. Next podcast.
>> Um, so, yeah, Matt wants to do away with derive any class. And as part of that, he also wants to do away with default signatures, which is used to provide a default implementation for a method on a type class where the default implementation has more constraints than what the type class has and the canonical example here is where you have a class where the class itself does not have a generic constraint, but you can provide a default implementation using generics. And so that has a generic constraint on there. Um, and he's suggesting that we get rid of it, I think, by replacing it with Iceland, Jack's favorite extension, deriving via
>> mhm. I mean, I I think that's a good thing because it's, ah, little bit confusing when you come across, you know, this default signatures, language language, language extension in real life because you're like, Wait a second. What's going on here? Um, I think yeah deriving via would have been a much better option here.
>> Yeah, I think a long as the deriving via solution subsumes what you could do with derive any class and default signatures. It's a no brainer. Uh, it seems like a lot of people who write generics code, though. Ah, and provide implementations in their libraries. Ah, use those two things together. So I don't wanna I don't want to make their lives harder and be able to derive less of our ecosystem.
>> I think they're equivalent in power, at least for type classes that only have one type parameter for multi parameter type classes. I think deriving via doesn't work so well because you can't, like, switch arguments around. Everything has to be. You know, you can only leave the last spot empty on. And I don't remember if he gets to that later in this post, Maybe he does. But that's the only thing that comes to mind for me.
>> I'm sure I've seen some, like, deriving via compose before. I don't know if that lets you get around that
>> maybe listeners please let us know because I'd be happy to be proven wrong about deriving via not working for multiple param type classes.
>> And then the next thing he wants to get rid of, he's just on a tear here of getting rid of stuff is generalized new type deriving, which is the one that lets you delegate your instance to the type that you're wrapping. So it's not done generically, and it's not done stock. It just takes, like if you're a wrapper around text and you're deriving to JSON, it'll take text's to JSON instance and use it for your type. He doesn't want that,
>> but yeah, because you can just do that with deriving via, like, why not?
>> these are things that are already possible, which is funny. He's just saying like, Hey, why don't you style your code this way rather than that way? Uh, you know, less extensions, less hand waving. And, you know, you only have to say, Okay, what does deriving via do? And at that point, you know, if you can focus on that, you're not necessarily yeah, tied up in all the other language extensions you're using.
>> Yeah, and it's funny. It's what Cody recommended at the top of the show. A lot of this stuff could be I mean, uh, maybe morally could be an HLint rule. I don't know if HLint can actually do this at the moment, but it is the type of thing that a linter could do for you.
>> Yeah, for this one, specifically for generalized new type. Deriving to play devil's advocate a little bit here. The only argument I could see is that the generalized new type deriving is a little bit shorter and you don't have to specify text. Uh, but it's not explicit. Uh, so I I try to keep in mind arguments about keeping boilerplate down. Ah, at the forefront because I think they make a huge difference, especially when everything comes together. But here I think it's clearly not enough boilerplate make a difference.
>> Yeah, And to me, the main win is not the boilerplate. It's that with that long list of, uh, type classes that you derive, you can be challenging to know. Oh, that's a stock type class. That's how it's going to be derived. That one has a default signature. So that's how it's gonna be derived. And to JSON has, uh, that's going to go through generalized new type deriving, and you can kind of build that intuition. But why bother when you can just do derive via?
>> Yeah, but I mean kind of what to Cody's point here is we now have to. If we change this underlying type of user, ID. We're gonna have to make sure we update it in the via instance, or else we're going to get some serious side effects.
>> That's true. It might fail to compile. I'm not 100%. And it probably depends on what type you change the inside of user ID to be
>> right. Yeah, If they're not, I forget the word uh, it goes by coercible I think.
>> Yeah, and I think that's actually one other difference between generalized new type deriving and deriving via. Is that with generalized new type deriving? I think it literally uses, like the same instance, dictionary behind the scenes, whereas with deriving via it builds a new instance dictionary that happens to call coerce for all of these things. So maybe there's a difference in runtime performance, although I doubt it would matter. In practice,
>> there is not. There's a there's a paper a while back, I think five or six years ago, Uh, not a paper. A Talk by Simon Peyton Jones, which is zero cost coercions. So as long as that title is equal. No loss in performance.
>> Excellent. Thank you, SPJ
>> Nice. Well, then he kind of, you know, keeps on his tear here with another removal, getting rid of the deriving strategies language extension, which I don't have a feeling one way or another. Here it seems like less is better
>> when there's only two choices, and one of them is syntactically obvious with that keyword via why do you need to specify stock with the other one?
>> Yep. Totally in favor of This one if, Ah, if you If you remove ah stock, then there's no point in having that.
>> Yeah, I really like how he does this to where this is like, we're building steps here. Like, if we do this, then Oh, look, we can also do this, and then it just gets simpler and simpler as you go along.
>> Yeah, I think this is like, yeah, I love that I love that is just, like building on top of each other, because for me, I'm like, Oh, my gosh, I can see how, like this one little change can lead to this more structural large change that, you know, I can reason better about it rather than be like we're just gonna do this boom like, Okay, Why not Now we have Why, uh, here in this blog post. So I really appreciate that.
>> Yeah, that's a good skill to have. It could be challenging sometimes to, you know, have an intuition and have an end goal in mind and then also be able to break it down into the constituent parts and show all the simple steps in between.
>> And I don't know that Matt meant this as a serious post. I'm pretty sure that he didn't. But another upside of having these small pieces that build on each other is that if he did want to turn this into, like a real GHC proposal, each one of these could be done individually, and it wouldn't be too big of a change at each step.
>> Uh, first I took it at face. Value is, it's a joke, but it's starting to seem like a pretty serious joke. I'm not so sure.
>> I mean, he seems to have some passion about it. I mean, he's really taking his time here and really kind of diving in.
>> Yeah, it's It's either a dedicated bit or he's serious. Um, and now, after we've removed all of these things, finally we're on to He wants to add something or allow some new thing. Um, and this is, uh, in the same way that you can do underscores in type signatures or type applications, toe like plug in some type there. He's suggesting a new use of underscores on deriving clauses to allow plugging in some types.
>> Ooh Ah,
>> Uh huh, Yeah. I I'm a big fan of the wild cards anywhere we can get them that they make sense. Uh, sometimes you sacrifice a little bit of readability, but, um, if if you keep using them, that is, uh, But if you use them as tools to figure out what the types would be, what the valid types would be, that's that's awesome.
>> Yeah, And this would remove that, like, worry that I had earlier about like, Oh, you change the underlying type. Well, this underscores gonna figure it out. So that also leads me to believe that I was incorrect in my previous assumption that this would probably call cause a compilation error if it was the wrong type.
>> Yeah, I do like how this ends up looking, but my main complaint with it is that it starts to remind me a little of like, um Scala or PureScript or Clojure, where they have these kind of magical symbols that mean a lot of different things in different contexts and underscores already that in Haskell. So, like it can mean for a type application, it can mean I am intentionally not supplying this argument. Whereas for a type signature, it can mean GHC Tell me what to put in here or if you have the partial type at what? Partial type signatures language extension on it means I'm not specifying this one. So and it means 1,000 other things too. I think type classes has a whole page listing all of the things. it can mean,
>> you, uh, totally threw me off there. I was like, Wait, it has multiple meanings. I guess I just sort of internalized them or something. I was struggling to come up with what you meant. Uh, yeah. Just took me a second.
>> Yeah, it has a lot of meetings, especially now with typed holes and type applications. And yeah, but anyway, I'm in favor of this. I think it makes sense. It's like a you know what should go here. So don't make me spell it out,
>> right or maintain it
>> and keep it up to date, like you were saying. And now we land on something that I think is actually a little divisive. Maybe which is removing attached, deriving, which really means turn on standalone deriving and make that the only way to do stuff right and stand alone. Deriving is where, instead of hanging the deriving clauses on the data type. They're all separate top level declarations.
>> Yeah, I would also be on the I Don't really want to do this style. Um, because I mean, in the current state of stand alone deriving like that's a ton of boilerplate like that's a lot off stuff to see. Um, yeah, it still reads fairly well, in my opinion, like just looking at the example here, like it seems readable. But it does seem like unnecessary.
>> Yeah, and it's funny because we were just talking about how Matt did a good job building these things step by step. But I feel like here he put these steps out of order because the next one is about removing boilerplate from the standalone deriving. So I feel like that one should come first. And then we get rid of the non standalone deriving,
>> right? I agree, because, ah, the improved syntax for stand alone that makes it a lot lighter weight. Then it's like, Okay, those those are definitely close enough. And this can fit into this whole plan of subsuming all these things.
>> Yeah, so maybe flip flop, the order those and then we can kind of be more on board with all right? Yeah, like standalone deriving is not too bad,
>> right? And so the lightweight standalone syntax That's the next section here. And I think essentially what that does is instead of requiring you to put one type class per deriving declaration, you can put a bunch so you can remove a lot of the duplication.
>> Yeah, there's some nesting there, which that gets a little bit confusing. But at the end of the day, like I can still parse it,
>> right? Yeah. Start duplication sometimes I do. Sorry, Taylor. Uh, sometimes the duplication though Makes my eyes start glazing over.
>> Yeah, for me. I kind of prefer reading the duplicated version because it's very clear I'm deriving this instance for this type, but I know that I wouldn't want to write that. And I would probably end up having like, a snippet in my editor that just plonks that in there already copy pasting lines all over the place. Um, and the really compact, non duplicated version I would probably prefer to write, but looking at it, I really have to think like, OK, this is the type these are all the classes. This is where everything plugs together and I could figure it out, but it takes me a bit longer.
>> Yeah, but that's also because it's not a normal thing, right? Like, if it was a normal day to day interaction with Haskell, then yeah, we'd be like, All right, we know what this is doing. So I mean, this is a proposal, right? Like air quotes around that, Um and so you know, not everything in here is gonna be something we're like, Yeah, we're totally get used to that because it's new. It's a change. It's different than what we're normally used to. So I think that can always, you know, people don't like change. We know this first hand at ITPro because we're, you know, currently updating how our user experiences our courses. And, you know, we're getting some pushback because, like, Well, we don't We don't want to change. We have this certain workflow we're used to and so like that. Same for Haskell. Developers like we're all used to our workflow and so jump something different is gonna rub us the wrong way.
>> Mhm. And now we're getting to the really interesting stuff which is removing stock deriving. So all of the type classes that the report specifies and that we added as our very first step in this process. Let's get rid of all of them and instead, add a new type in base somewhere or actually, it may already be provided. I don't know if it does not, but some new type called stock. And if you want stock deriving, you go via stock. Otherwise, you go via something else. I think this is pretty clever.
>> yeah, I agree with that. Um uh, I, uh it's kind of like lisp does where it goes to extreme, of building up all of its standard library of itself. I think with things like internals defined, like everything else, uh, people will be more likely to be able to understand things and contribute as well.
>> Yeah, it is a little mind bending to see deriving generic via stock and then deriving to JSON via generically. It's like, Okay, so that would carry the one. Okay,
>> this is how we did. Yeah. I mean, from this example that's in this section, you know, I'm also like, Well, why do we even still have those underscores? Like, couldn't we figure out how to a way to like, get this thing to in for what type it is.
>> Yeah, well, because sometimes you want, like if you derived via text, you don't reference to your type it. All right, so you do need that underscore in there, but it would be nice if you could get rid of it. Like if it's a type that accepts one more parameter, go ahead and plug the type I'm deriving for in there. Be pretty sneaky.
>> Yeah, anywho.
>> And then we get to the last suggestion here, which is actually, uh, kind of a reversion of one of the earlier ones. Or like an alternate path to take, which is to remove standalone deriving. So previously we were talking about only having, I guess, stand apart or only standalone, deriving, not attached arriving. And he's suggesting that instead you could only have attached arriving. But I don't really get why he suggests this.
>> Yeah, I don't super get it either. I think the posts was good on its own. This was just kind of a little like I know you guys were all mad at me for saying, you know, get rid of attached deriving. So here's what we could do if we kept attached arriving and got rid of standalone deriving. But we really still need standing on deriving in those instances where we have to create an orphan instance or specify, you know, a context for a global ADT or GADT
>> Generalized, not global. I'm just I'm just out of this world, man. I'm all about this world, man. I'm just global,
>> but yeah, I think it's interesting that, like a language like PureScript doesn't even allow orphan instances whether or not you derive them. But with the changes he suggested so far, you would not be able to derive an orphan instance or sorry you would be able to. But if you want with this remove standalone deriving, you wouldn't be able to And maybe that's a good thing. You shouldn't be doing orphan instances except there was a post. Maybe last week or the week before That was suggesting your orphan instances are Probably fine.
>> I mean, sometimes you got to, you know,
>> right, So if this was this was sort of a concession, I'm betting that since this wasn't since this was a concession, uh, that he has something in mind to be able to still derive orphan instances. Because that's an even more divisive thing.
>> Yeah, I agree with Cam. This seems kind of tacked onto the end. I'm not clear what he's going for here.
>> Yeah, but I mean, at that point, we're at the end, right?
>> We are yeah
>> He says the terrible post is over.
>> It wasn't that bad, Matt. It was a good post?
>> I agree.
>> Yeah. Good ideas. Like a like I tweeted. I think I love this. Have looked at a few more times. I still like it very much. Maybe love it? Not sure, but a lot of good things in here.
>> I really like how this, um, simplifies the Haskell language by drilling down on something that we're all familiar with. And I think we have become accustomed to and maybe a little blinded by the amount of complexity that's hidden there. So, like, we don't really think twice about turning on all these deriving extensions, mostly because we hide them away in our package descriptions. So, like our cabal file, just has deriving star turned on pretty much and in our code most of the time, we're doing either stock deriving or generic deriving. So it's just in that list of stuff. So, like day to day, it's not that big of a deal. But reading through these changes makes me think like, yeah, there's a lot of room for improvement here. And as a side effect, the language report gets simpler, and that's good to see.
>> Always, always a positive, right?
>> yeah, I'm definitely in favor of simplifying things, removing foot guns. I do wanna be careful not to remove some of the features that power users use, but that that's something that's sort of a case by case basis.
>> Yeah, And what would the backwards compatibility be for something like this?
>> I think none.
>> Don't upgrade your GHC or use lots of the C pre processor.
>> Yeah, No, I feel like we need some sort of, uh, way to upgrade. If that were the case, if we should do something like this
>> Well, I think realistically, if the's were proposed and were accepted and were implemented, it would be like the There's a warning now in GHC for not providing a deriving strategy when you derive. So would be, I think, similar to that where we would add the new behavior and potentially add a warning so that you could upgrade your code and then two or three versions from there we would remove the old behavior.
>> But also, I think nothing like this has been done before with GHC. So who knows what they would do?
>> Fifth cool. Well, anyways, Matt, it was a great post. I would encourage all of our listeners to go check it out.
>> Agreed? I had fun walking through it with you all.
>> Same man same.
>> All right, well, I think that will do it for us. Um, Cody, any closing thoughts about this post?
>> Um, no, I I agree with it. In general, I really wanna simplify the Haskell language. Uh, I will say, uh, not at any cost. That's an important one, but definitely want to strip off some of these things and unify these concepts.
>> Yeah, All right.
>> Thanks for listening to the Haskell weekly podcast. The Haskell weekly podcast is brought to you by ITProTV the e learning platform for IT professionals. Also our employer. And they would love to an extend an offer for 30% off the lifetime of your script subscription. Wow, that's a really hard word to say. Subscription with the promo code Haskell Weekly 30 All one word No spaces. Capitalization doesn't matter. Um, and that will give you 30% off the lifetime of your subscription. So please, please, please go check it out. If you're interested, go see the content. Also, if you're not quite sure, please sign up for a free membership. That way you can kind of see what there is. We would love to see you on the ITProTV platform.
>> We sure would. And that will do us do it for us this week. Uh, once again, I've been your host, Taylor. And with me today was Camera and Cody from my team. Um, if you want to learn more about Haskell Weekly, you can check out our website Haskell weekly dot news, where you could sign up for our newsletter, subscribe to this podcast, and, uh, find us on social media like Twitter. YouTube. GitHub. Reddit. I don't know what else is there out there everywhere. So Yeah.
>> We're not on Runescape yet. No. Sorry. Thanks for listening. And we'll see you next week.
>> See you