How to learn language extensions

One thing you can do is ask GHC to translate your Haskell program to STG (with -ddump-stg-final) which has a much more well-defined and simpler operational semantics.

Without optimizations the example from the stackoverflow question becomes:

func =
    \r [x]
        let { k = \u [] bat x; } in
        let { j = \u [] baz k; } in
        let { sat = \u [] let { sat = \u [] bar j; } in  + $fNumInt sat j;
        } in  + $fNumInt sat k;

Which shows that it allocates thunks for k and j and for the left operand of + and then it calls the + function with the Int instance of Num.

With optimizations it is:

$wfunc =
    \r [x]
        case bat x of k {
        __DEFAULT ->
        case baz k of j {
        __DEFAULT ->
        case bar j of {
        I# x1 ->
        case j<TagProper> of {
        I# y ->
        case k<TagProper> of {
        I# y1 -> case +# [x1 y] of sat { __DEFAULT -> +# [sat y1]; };
        };};};};};

func = \r [x] case $wfunc x of ww { __DEFAULT -> I# [ww]; };

Which shows a much more direct evaluation of bat then baz then bar and finally the addition.

2 Likes

So how did you learn this? I tried looking at the core language a few times but it never helped me in any way.

I am aware that there are a bunch of articles I could read, say Implementing lazy functional languages on stock hardware: The spineless tagless G-machine by Simon @simonpj. Is this how you learned and would suggest one to?

Is there a way to write straight in the STG language and have GHC run it? This would allow for a writing of a tutorial, where you do something and spectacularly stuff happens. It would be much better to start with than theory. I like me a tutorial.

Right now, I am afraid to say, this STG code does not show anything to me at all. I do think this is a good advice, I only need to find a way to follow it.

1 Like

I guess mostly through osmosis – hearing things like “in STG let directly corresponds to allocation and case to evaluation” – and lots of experimentation, seeing which programs produce which STG code.

One thing that helped me was to ignore the parts I did not understand. Just recently I came to know what the difference really is between that \u and \r. And I still don’t know what that <TagProper> means.

I did not learn it from SPJ’s paper. I think it is a decent academic description, but rather abstract and presenting all the details straight away. Instead I think it would be better to have a tutorial that builds up from a simpler language to the full STG machine in several steps. Perhaps I could try to write something like that if I can find the time.

There is the external STG interpreter, but I believe it is not that easy to use yet.

6 Likes

It would be fantastic, please let me know if you do.

To get more out of reading Core, you might enjoy this talk: GHC Core Optimisations - Sebastian Graf - 2023 GHC Contributor's Workshop - YouTube

@bgamari’s talk from the same event has a section on reading STG syntax as well.

4 Likes

Ah, I wanted to link Ben’s talk, but couldn’t find that section quickly. And of course understanding Core is the first step to understanding STG.

That said, I hope there will be a full presentation on STG next year.

1 Like

Thoroughly bad idea. (What you quote is at best misleading.) What’s more, O.P. is asking whether something has changed wrt FlexibleContexts – or at least why the User Guide seems to have changed. See my answer above: AFAICT, there’s been no change in behaviour; there’s been some ‘rationalisation’ of the structure of the Guide.

Whoa! 30 years ago the pre-eminent compiler was Hugs. GHC was playing catch-up. And the restrictions on Contexts were entirely sensible for a wholly new thing: TypeClasses/Instances/therefore Contexts were the innovation in Haskell; no other language (functional or otherwise) had anything like them.

I several times above mentioned FlexibleInstances. Those weren’t allowed as at 1990 because they’d lead to OverlappingInstances. And everybody was highly nervous about that (rightly so). If you don’t have FlexibleInstances, you don’t need FlexibleContexts.

Overlapping Instances – especially combined with other extensions like MultiParamTypeClasses and FunctionalDependencies are a nest of vipers. That’s why FlexibleInstances (and therefore Contexts) were kept out of Haskell 1998 although both main compilers already supported them; and still kept out of H2010.

Note that the Prelude doesn’t “need” FlexibleInstances nor Contexts. So it’s not like omitting them is cramping your Haskell style.

2 Likes

The Hugs 98 User’s Guide - 4.2. Compiling modules that use the Foreign Function Interface

…? Or are you getting confused with Gofer (Hugs’s predecessor) - I think it had a gofcc command for compiling Gofer to C…

1 Like

I feel some apology and gentle encouragement is due to O.P. This thread has rapidly veered away from learning about extensions into areas no newbie or even intermediate Haskeller needs to understand.

I suggest those who want to talk about type inference and STG/core/dumps split all that stuff on to a train-spotters thread.

2 Likes

Ok, I was talking loosely: Hugs is an interpreter, not a compiler. The difference when talking about extensions doesn’t seem material.

I am not sure if your intention is to correct a possible factual error in what I said, or to add more information, or something else… This is all history for me: I have not been writing any Haskell back then. So, I may be wrong in the range of dates — but what you are saying seems to corroborate what I said. I cannot really tell what emotions the «whoa» should convey, since this interjection is outside of my cultural context.

I should be glad to do so but I reckon it requires moderatorial powers.

Bragilevsky’s book has a chapter on ‘Type system advances’.

1 Like

I thought so as well until I tried to implement the extension, got very confused, and discovered this issue. It’s a flaming trashcan. Or put otherwise, it’s exhibit B as to why you can’t just keep piling extension upon extension to a 25 year old language standard. Exhibit A is the the Prelude of course.

2 Likes

To be frank, is there any commonly used extension that will break your code in a way it’s never been broken before? Have you ever contemplated “should I really turn on extension X, or can I get away without it”? The only extension I’ve ever had problems with was PolyKinds. I have never personally had code review rejected because “I turned on some questionable extension”. I never had to defend a usage of any extension.

As OP is “relatively new to Haskell” and asked about “how others approach learning language extensions”, I’d definitely advise just turning on what the compiler suggest you to turn on, and learn via examples. Reasoning about how a specific extension/optimization changes the way GHC optimizes/executes your program (actually, reasoning about most things GHC does) is waaaay above the entry level, and not many people are able to do so. And every now and then, we see contrived examples of unwanted GHC behaviours popping up. So I’d say, turn things on, have fun, and don’t think much about details (yet!).

3 Likes

Sorry but this is terrible advice. You need to understand why your code doesn’t compile without the suggested extension. If you don’t, it’s more likely that your code is wrong than you just forgot to enable an extension. For example, one common GHC suggestion nowadays is to enable AllowAmbiguousTypes, but that would usually be a mistake.

3 Likes

But OP will know why his code doesn’t compile, GHC usually prints a rationale behind why a particular extension is needed.

Btw, best learning is learning by mistake. If I turn on a bad extension and get a different error, I’d roll back and read more. This is a learning process. Experimenting. No reason to be correct first try all the time. I don’t know why people seem to be so strict about stuff that should naturally come with trial-and-error experience.

3 Likes

Nothing bad has ever happened from bashing your brain with ghci :slight_smile:

Seconded. And that example came to my mind immediately: AllowAmbiguousTypes GHC readily recommends you switch on. Almost certainly it will just lead a newbie into further trouble.

Not in this case. And usually in this case, it’s because there’s a typo in the signature, not because a newbie is intending to do something fancy…

I think the AllowAmbigousTypes note could just use some extra qualifiers - no need to throw it out. Because it is a useful pointer if you’re actually writing code like that (ime, many Haskellers naturally end up wanting it for certain things).

But an extra pointer saying “if you don’t want this, it’s probably some other issue” would be a nice addition.

Just no. This is more terrible advice. As this thread (esp @blamario) is pointing out, GHC’s habit of (attempting to) document each extension as if it’s orthogonal to the others gives a newbie no support when they get into deep water. Especially when GHC’s message suggests switching on a further extension. Note what’s bad about AllowAmbiguousTypes is there’s no new syntax enabled: if you intended to use (say) MultiParamTypeClasses you at least need to declare a class with multiple params before GHC suggests that extension.

Rather than “roll back and read more” a lot of newbies will conclude Haskell is too hard and abandon the language. And frankly GHC is too hard. Haskell 2010 + a small set of extensions isn’t; and I wish there were a way for a newbie to say: please don’t go suggesting exotic extensions.

"… and abandon the language. "

BTW O.P. seems to have fallen silent on this thread. I hope they’re not scared off already.

2 Likes