Skip to content

[PR-1091] Article about type inference #2

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

Open
wants to merge 3 commits into
base: master
Choose a base branch
from

Conversation

Heimdell
Copy link
Contributor

@Heimdell Heimdell commented Oct 6, 2021

No description provided.

</td>
<td>
the type of all types (including the `Type` itself)
</td>
Copy link
Contributor

Choose a reason for hiding this comment

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

Do we have a sort of TypeInType? Is it for simplicity? I would emphasise this moment in more detail.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, exactly. Otherwise I have to use either additional Box or a hierarchy, which requires Nat-s and their arithmetics to be somehow present.

type Refeshes m :: Constraint

refresh :: Refreshes m => Name -> m Name
```
Copy link
Contributor

Choose a reason for hiding this comment

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

Do you have an implementation of refresh? Without that, the section looks a bit incomplete to me.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I do, will add.

Using that, we can return scope-correct programs right off the parser.

_Pro tip learned after a debug session_: Refreshing names of records field declarations in record literal is a bad idea.

Copy link
Contributor

Choose a reason for hiding this comment

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

To me, it's worth explaining why this is a bad idea in a couple of sentences. The reader might not get your point.

We can construct the program. Before we're doing inference, we need an auxillary mechanism. It whill compare two types and either find a set of substitutions to convert both to the same type, or bail out with error if that isn't possible. This mechanism is called unification.

Usially, in Hindley-Milner inference, the type of unifier is

Copy link
Contributor

Choose a reason for hiding this comment

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

It's worth referring to some paper on Hindley-Milner inference to make the post more self-contained.

unify (Lam n t b) (Lam m u c) = do
unify t u
unify b (subst (Bound m ==> Rigid n) c)
```
Copy link
Contributor

Choose a reason for hiding this comment

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

why do you repeat unify (Lam n t b) (Lam m u c) = do twice?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

unify (Pi n t b) (Pi m u c) = do
  unify t u
  unify b (subst (Bound m ==> Rigid n) c)
unify (Lam n t b) (Lam m u c) = do
  unify t u
  unify b (subst (Bound m ==> Rigid n) c)

Where? The first clause is for Pi-types.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

They just appear to have the same unification procedure.

axiom "True" Bool
axiom "True" Bool
axiom "Bool" Type
```
Copy link
Contributor

Choose a reason for hiding this comment

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

Are these something like inference rules for values?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, they are runtime constructor reps, with the type.

)
=> AST
-> Sem m AST
```
Copy link
Contributor

Choose a reason for hiding this comment

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

What is Sem?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

infer t

let k = telescope args Star
check k Star
Copy link
Contributor

Choose a reason for hiding this comment

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

Wow, the key place. I would explain what telescope is.

Copy link
Contributor

Choose a reason for hiding this comment

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

In a couple of words, ofc. There's no need to write a monograph about that.

infer b
```

In case of mutually-recursive definitions, theor bodies (but not the types!) might depend on each other, so we have to bind the constructors to whatever is present in the declarations and do the inference only _after_ we enter the block context.
Copy link
Contributor

Choose a reason for hiding this comment

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

their bodies?

## Conclusion

The presence of the typechecker not only allows you to "prevent programs from crashing", but also - if the type system is powerful enough - to partially shift your work onto compiler, by forcing it to implicity calculate some types and, potentially, generate code from them.

Copy link
Contributor

Choose a reason for hiding this comment

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

I guess the post requires a further reading section.

And mentioning our post written with Vlad :pled:

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.

2 participants