This Engineering Notebook post explains why type inference (and checking) 
is much easier than I ever imagined.


For over a decade, I believed that (while doing type inference) *everything 
depends on everything else*. I thought inferring the types (of objects) in 
module *A* required inferring the types in all other imported modules M1, 
M2, etc. That's just wildly wrong!


Aha! It's dead easy to know the types of *names *imported from other 
modules!!!


- "Import" statements *only* give access to top-level *names* from other 
modules.

- Top-level declarations (in other modules) explicitly state the types of 
imported names.


Let's take a closer look. The top-level statements of any module consist 
only of import statements, assignment statements, and definitions of 
classes and functions. Annotations give us the types of names in the LHS of 
the assignments. The types of classes and functions are the classes and 
functions themselves.


The paragraph above contains some hand waving. Let's look at two 
difficulties:


*The import graph*


Imports statements create an implicit graph of *import dependencies*. mypy 
devotes considerable code to discovering strongly connected components 
<https://github.com/python/mypy/wiki/Build-Manager> (SCCs).


These dependencies matter because changing module A might require 
reanalyzing modules that import A. Otoh, changing module A only *actually* 
matters 
if the change involves a top-level name in A.


The dependency graph gives a *new view of Leo*. *By design, *the following 
are true:


- leoGlobals.py imports no Leo modules, only Python library modules.

- leoNodes.py imports only leoGlobals.py and signal_manager.py, which does 
not import any Leo imports.

- leoCommands.py only imports leoNodes.py at the top level. 
*Commands.__init__* imports all of Leo's sub-commanders.


These constraints (and others) ensure that Leo contains no circular import 
dependencies.


In short, it's non-trivial to compute the dependency graph! A prototype 
might sidestep such complications--perhaps by using a hand-crafted 
dependency graph.


*Function arguments*


The only remaining difficulty involves inferring the types of 
function/method arguments. The Hindley-Milner so-called "algorithm" does 
this. This algorithm takes a *context* comprising the already-inferred 
arguments.


I don't understand all the details. Happily, the details don't matter if 
(as in Leo) all arguments have annotations!


*Summary*


Type inference and checking remain tricky. But the details involve 
bookkeeping, not deep theory!


The Hindley-Milner algorithm isn't needed if all arguments have annotations.


These Ahas open the door to a super-fast *Leonine pylint*, as I'll explain 
in another ENB. This Leonine *pylint* should be about as fast as the 
existing Leonine *pyflakes*.


Edward

-- 
You received this message because you are subscribed to the Google Groups 
"leo-editor" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/leo-editor/f183bd4d-2257-4855-9556-1dd8b220fc3bn%40googlegroups.com.

Reply via email to