Skip to content

Fix ambiguous type error example#144

Open
MatthijsBlom wants to merge 5 commits into
learnyouahaskell:mainfrom
MatthijsBlom:ambiguous-type-example
Open

Fix ambiguous type error example#144
MatthijsBlom wants to merge 5 commits into
learnyouahaskell:mainfrom
MatthijsBlom:ambiguous-type-example

Conversation

@MatthijsBlom
Copy link
Copy Markdown
Collaborator

@MatthijsBlom MatthijsBlom commented Mar 12, 2026

Due to ExtendedDefaultRules being enabled by default, GHCi no longer produces an error in the example about ambiguous type variables.

This change amends the original explanation.
It explains the new situation in GHCi, and compares with and elaborates on GHC's behavior.

Fixes #25

@ulysses4ever
Copy link
Copy Markdown
Collaborator

Thank you for submitting this patch! I'll try to review by the end of the week.

@ulysses4ever
Copy link
Copy Markdown
Collaborator

In the meantime, it'd be great if you could resolve the conflicts.

@MatthijsBlom MatthijsBlom force-pushed the ambiguous-type-example branch from 22ffc40 to 4c6f98c Compare March 13, 2026 15:31
@MatthijsBlom MatthijsBlom force-pushed the ambiguous-type-example branch from 4c6f98c to 26f0b70 Compare March 13, 2026 15:38
GHC even tells us as much: whatever the type of `four` is, it must be part of `Read`.
But it can't tell that it is, because it doesn't know the actual type: it is ambiguous.
Whereas GHCi at this point tried to guess, GHC does not.
Instead, it immediately complains and demands that we clarify the type.
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you and an example that type check and works in the end? E.g.

> read "4" :: Int
4

Copy link
Copy Markdown
Collaborator Author

@MatthijsBlom MatthijsBlom Mar 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are already several such examples immediately before this added section.

I tacked on the read "13" :: Bool example for contrast with the preceding examples, and also to demonstrate that the GHCi-guessed-wrong explanation is correct.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you still feel there should be an example of success further down?

If we used it as a boolean, it knew it had to return a `Bool`.
But now, it knows we want some type that is part of the `Read` class, it just doesn't know which one.
And sometimes, when it cannot figure out a type, GHCi tries to be helpful by taking a guess.
Not just any guess of course, but wrong in this case anyway.
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have you considered showing what guess it took? It's the unit type.

λ> :set -Wtype-defaults
λ> read "4"
<interactive>:6:1: warning: [GHC-18042] [-Wtype-defaults]
    • Defaulting the type variable ‘a0’ to type ‘()’ in the following constraints
        (Show a0) arising from a use of ‘print’ at <interactive>:6:1-8
        (Read a0) arising from a use of ‘it’ at <interactive>:6:1-8
    • In a stmt of an interactive GHCi command: print it

*** Exception: Prelude.read: no parse
λ> 

Maybe mentioning that it's the unit is enough. Otherwise, -Wtype-defaults may be a good candidate for a NOTE.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have, but I couldn't find a satisfactory way of figuring it out.
Even already knowing the answer, I failed to trace the exact route that led to it. I thought I remembered a default declaration with number types somewhere in base, but I couldn't find any default declaration that I'm confident is actually used (and remotely relevant).
There seems to be no way of listing all default rules in scope.

As it currently stands, nowhere in the book is there any mention of compiler warnings, compiler flags, :set, language extensions, or pragmas. Any first mention would likely require quite a bit of extra explanation.

-Wtype-defaults seems too specific. But it is included in -Wall.
What do you think about writing a suitable .ghci and recommending it early in the book?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And sometimes, when it cannot figure out a type, GHCi tries to be helpful by taking a guess.
Not just any guess of course, but wrong in this case anyway.

IMO, this is a little bit too vague, because it makes the reader feel that ghci behavior is a surprise. It is kind of tricky to clarify because () was not introduced yet. I am not totally sure how to solve this tension.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But it is a surprise, isn't it? 😏
I'd prefer GHC(i) just didn't do this by default.

() is in fact introduced earlier in this same chapter.
I don't think the bulk of the trickiness lies with (). But it sure is tricky.
I'll do some more thinking.

errors.haskell.org/messages/GHC-39999 seems outdated, by the way.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think my preference would be to add a .hintbox here with a reference to a yet-to-be-written appendix specifically about type variable defaulting.

There is a lot to be explained (extensions/settings, GHCi vs. GHC, default rules, the defaulting mechanisms, possibly warnings, possibly interaction with the monomorphism restriction), and probably several examples should be included. Including all this in this chapter would, I feel, disrupt the text too much. But defaulting is still worth discussing. Therefore: split it off.

What do you think?

If this way is chosen, I'd prefer to defer adding this appendix to a future PR.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, perfect is the enemy of good.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added b22f71a for now.

Copy link
Copy Markdown
Collaborator

@pierluc-codes pierluc-codes left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My apologies, I put a lot of comment on your work: do not take that as a criticism of the quality of the work. I really appreciate your changes here.

I especially appreciate the effort of keeping the tone of the rest of the book.

Thank you!

Comment thread source_md/types-and-typeclasses.md Outdated
Comment thread source_md/types-and-typeclasses.md Outdated
If we used it as a boolean, it knew it had to return a `Bool`.
But now, it knows we want some type that is part of the `Read` class, it just doesn't know which one.
And sometimes, when it cannot figure out a type, GHCi tries to be helpful by taking a guess.
Not just any guess of course, but wrong in this case anyway.
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And sometimes, when it cannot figure out a type, GHCi tries to be helpful by taking a guess.
Not just any guess of course, but wrong in this case anyway.

IMO, this is a little bit too vague, because it makes the reader feel that ghci behavior is a surprise. It is kind of tricky to clarify because () was not introduced yet. I am not totally sure how to solve this tension.

Comment thread source_md/types-and-typeclasses.md
Comment thread source_md/types-and-typeclasses.md Outdated
Whereas GHCi at this point tried to guess, GHC does not.
Instead, it immediately complains and demands that we clarify the type.

Most expressions are such that the compiler can infer what their type is by itself.
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this part should be moved.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I considered doing this as well. In the end I kept it because of its final line, because I thought the repetition wouldn't hurt, and because it seemed to flow better into the next section.

I'll do some thinking about how to incorporate the last line's information somewhere else.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in 73a8fd1.

Comment thread source_md/types-and-typeclasses.md Outdated
@MatthijsBlom
Copy link
Copy Markdown
Collaborator Author

My apologies, I put a lot of comment on your work: do not take that as a criticism of the quality of the work. I really appreciate your changes here.

No worries!

I especially appreciate the effort of keeping the tone of the rest of the book.

Good to hear that this has apparently been successful.

@MatthijsBlom MatthijsBlom changed the title Fix ambiguous type error example (#25) Fix ambiguous type error example Mar 15, 2026
@MatthijsBlom MatthijsBlom force-pushed the ambiguous-type-example branch from be8a30c to 2769361 Compare March 26, 2026 09:35
@ulysses4ever
Copy link
Copy Markdown
Collaborator

I promise I'll get to this one this month of April! Sorry for the delay!

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Example for "ambiguous type variable" error doesn't work anymore

3 participants