
“What part of Milner-Hindley do you not understand?” - tikhonj
http://stackoverflow.com/q/12532552/286871
======
emillon
Hindley-Milner (never seen it written as M-H) is beautiful because it's an
elegant extension of simply-typed lambda calculus (STLC) that brings a very
useful trait, polymorphism.

Here the first 3 rules are those of STLC. The magic happens in [Gen] and
[Inst]: namely, you can generalize free type variables. If you have a function
that works on lists of elements of type t when there is no constraint on t,
they can work on any lists of any type. This brings quantification to the type
system, ie you go from:

    
    
        ∀ a. reverse : α list → α list
    

to

    
    
        reverse : ∀ α. α list → α list
    

(in the first one, ∀ is part of the discourse, and in the second one, part of
the type). [Inst] states that you can replace a quantified variable by any
variable. This is the role of the ⊑ operator, which is unfortunately not
explained in this notation. This is confusing for people not used to type
systems, ie most people).

Technically, [Let] is redundant because it is a combination of [App]+[Abs] :
let x = e1 in e2 is equivalent to (λx.e2) e1. There is a difference in the ML
branch of languages (as opposed to the Haskell branch) because in the presence
of memory references (mutable cells) you can't generalize everywhere, so only
let-bound variables are given a type scheme σ (both in the let...in construct
and in toplevel phrases). That's why there is usually an explicit
generalisation step at this point. Or maybe I have overlooked this particular
presentation. HTH

~~~
benbataille
> Technically, [Let] is redundant because it is a combination of [App]+[Abs] :
> let x = e1 in e2 is equivalent to (λx.e2) e1.

This equivalence does not hold in the HM formalisation. It's well explained in
the Wikipedia article : <http://en.wikipedia.org/wiki/Hindley-Milner#Let-
polymorphism>

[Abs] is monomorphic while [Let] is polymorphic. Using the Wikipedia article
exemple : \f.(f true, f 0) will not be typed while let f = \x.x in (f true, f
0) will be reduced to (bool, int).

~~~
groovy2shoes
Does the nonequivalence have something to do with ML's value restriction?

~~~
benbataille
No, this nonequivalence applies directly to the typing of the lambda-calculus
which was the topic of the original papers by Hindley and proven by Damas.

On the contrary, the value restriction is a part of the extended rules used
for the typing of ML. It was introduced because ML isn't pure, it supports
references. The value restriction is there to prevent them having polymorphic
type. The rule is simple : syntactic values are the only things receiving a
polymorphic type. What is a syntactic value ? To quote Geoffrey Smith notes on
SML97 "Basically, a syntactic value is an expression that can be evaluated
without doing any computation".

All this iss done in order to ensure type safety. Actually, if references
could have a polymorphic type, the type system would accept incorrect programs
such as :

let r : 'a list ref = ref [] let r1 : int list ref = r let r2 : string list
ref = r r2 := "a" let v : int = 1 + !r1

Which does not work because r, r1 and r2 are references to the same value.

Value restriction is a bit overkill. It rejects program which could be safely
typed. Other solution to this problem exists. Actually, Standard ML used a
different solution at the beginning (carrying information about the typed hold
in a cell along) but it has other drawbacks. MLTon has a really good page
about all that : <http://mlton.org/ValueRestriction>

Some research was done about relaxing value restriction. OCaml type system,
for example, has less constraints than SML and MLTon (you can see this paper
about that [http://caml.inria.fr/pub/papers/garrigue-
value_restriction-f...](http://caml.inria.fr/pub/papers/garrigue-
value_restriction-fiwflp04.pdf)).

~~~
Darmani
You may be interested to know that the value restriction is not there to
protect against unsafe programs. Rather, it is because polymorphic values get
elaborated to functions after type inference, which produces some
exceptionally unintuitive (but safe) behavior.

This is Karl Crary's explanation; here's the only online recording I've found:
[http://cstheory.stackexchange.com/questions/8892/type-
infere...](http://cstheory.stackexchange.com/questions/8892/type-inference-
for-imperative-statements-other-than-assignment/8897#8897)

~~~
rntz
You _could_ elaborate polymorphic values to type functions; and if you were
compiling ML to System F or System F-omega, that is certainly what you would
do. But in practice this might produce performance problems (I shouldn't have
to call a function every time I use the empty list just because it has
polymorphic type!). I must admit I'm not sure what SML and Haskell compilers
_actually_ do.

So in some sense the value restriction is there to prevent us from having to
make the ugly choice between unsafety on the one hand, and inefficiency and
unintuitive behavior on the other.

------
auggierose
His question is very valid. I got a math degree before I got a PhD in computer
science, and this weird notation was the hardest part about the switch. The
funny thing is, if you submit papers using a more sane and easier to
understand notation (like, notation more close to a functional program) then
computer scientists freak out and complain about notation. I predict this kind
of notation to be dead within the next 20 years, its just too ugly.

~~~
more_original
The inference rule notation is standard within mathematical logic, which is
where it comes from. I'm not an expert on the history of mathematics, but I've
seen inference rules for example in Gentzen's 1935 paper and I'm sure they are
quite a bit older.

I haven't seen a notation that is easier to read than inference rules. Writing
them as functional programs can be problematic, as the rules do not always
fully specify an algorithm. One judgement may have different derivations. If
one writes down algorithms, such as HM type inference, then one does in fact
often use notation in the style of functional programming.

Incedentally, rather than abolishing the inference rule notation, there are
actually tendencies to introduce them into programming:
[https://en.wikipedia.org/wiki/Epigram_%28programming_languag...](https://en.wikipedia.org/wiki/Epigram_%28programming_language%29)
(though it remains to be seen if this is a good idea)

~~~
jrabone
Given the JVM supports Unicode identifiers, and given the rich vein of
mathematical operators therein, I always thought it would be fun to do the APL
thing with Java. Scala went a (very) little way towards this, but I don't
think anyone has taken it to logical extremes yet.

(although I did once threaten my co-workers that I would tell the theoretical
mathematician on the team about Unicode identifiers in Java. He used to write
LaTeX in the Javadoc comments [which Doxygen handles rather nicely])

~~~
wtetzner
I believe Fortress used Unicode identifiers quite extensively.

<http://en.wikipedia.org/wiki/Fortress_(programming_language)>

~~~
riffraff
I believe you misremember. From what I recall fortress had an ascii syntax
where special combinations would be translated into symbols by the
doc/rendering system, eg NN would be rendered as (bold N used for natural
numbers).

------
andyjohnson0
<http://en.wikipedia.org/wiki/Hindley-Milner>

Wikipedia article for those who, like me, not only don't understand it but had
even heard of it before.

------
gtani
Hmm, H-M, AKA Damas-Milner, p 331 in TAPL (indexed as D-M only, so easy to
overlook, and I can't see where it's in Harper's Practical Foundations,
AFAICT.

As an aside, the other day i started flipping thru Harper's Lazy Eval writeup,
and found it surprisingly readable, even if i was skipping reading the rules.

<http://www.cs.cmu.edu/~rwh/plbook/book.pdf>

[http://www.amazon.com/Types-Programming-Languages-
Benjamin-P...](http://www.amazon.com/Types-Programming-Languages-Benjamin-
Pierce/dp/0262162091/)

------
sc0rb
A solid computer science education would have helped him understand this. Not
required for a 'normal' programmer but the more interesting parts of our trade
exist in Computer Science rather than Software Engineering.

~~~
tikhonj
Eh. The first time I saw typing rules in class was in a moderately specialized
graduate course, so it would have been very easy to get a perfectly good CS
education without learning about them.

Of course, I go to a university that seems very biased towards practical
engineering sorts of topics over theory, so your experience may vary.

~~~
Periodic
If you take a class in compilers you should see these sorts of inference rules
when talking about operational semantics. Though maybe it isn't as popular to
use operational semantics anymore. It's very useful to define rules in this
syntax when working on semantic analysis and code generation.

I didn't get the background really necessary to really understand the type-
theory parts of this notation until I took a graduate course in programming
language theory.

~~~
tikhonj
Yeah, at my school operational semantics was only covered in that same PL
theory course. The undergraduate programming languages/compilers course never
went into it, unfortunately.

------
fierarul
This brings back memories from my type inference work... Hindley-Milner is
very simple to understand, it's just the formalization that's too dense.

~~~
VikingCoder
Two professors were arguing in front of a chalkboard, for hours and hours.
Finally one of them nodded in agreement and said, "You're right, it's
trivial."

~~~
qu4z-2
I've been in situations like this. I'll give a simple rule set of some topic
that someone hasn't quite managed to defragment in their brain (and thus know
it as a bunch of rules and special-cases), and then they'll spend hours going
"But what if <x>?". Eventually they believe me that my simplified model is
equivalent to their overcomplicated internal model. The result is usually
closer to "You're right; it is that simple." but that's fairly similar to
"It's trivial."

In short: Often people need to try a lot of "Yeah, but what if <x>?" before
they satisfy themselves that something is in fact as simple as it appears.

------
xiaomai
Jeremy Siek also has a good intro to the notation:
[http://siek.blogspot.com/2012/07/crash-course-on-notation-
in...](http://siek.blogspot.com/2012/07/crash-course-on-notation-in-
programming.html)

------
pfortuny
Sorry, could not help it but this discussion has turned into something pretty
familiar:

INIGO: You are using Bonetti's defense against me, eh?

MAN IN BLACK: I thought it fitting, considering the rocky terrain.

INIGO: Naturally, you must expect me to attack with Capo Ferro.

MAN IN BLACK: Naturally. But I find that Thibault cancels Capo Ferro, don't
you?

INIGO: Unless the enemy has studied his Agrippa... which I have!

~~~
omegant
And this belongs to?

~~~
pfortuny
Just read the above discussions and get a laugh. Yes, I know it is just a joke
but... not much so, if you think of it.

Ah, discussions between set theorists and logicians, those were the days.

~~~
omegant
The quote was familiar but I couldn't remember the source. The meaning is
clear though! Amazing neverending discussions, it makes me remember the
Feynman anecdote when he observed matematiians discussions.

------
dman
Whats a good book to pickup the notation used in the stack overflow link?

~~~
spacemanaki
The first edition of PLAI has a nice introductory chapter on types that
explains this notation and has a whole section on type inference. It's also
freely available online, so that's nice. (chapter 10 is on types) I haven't
looked at the second edition at all yet, but the chapter on types looks like
it has more code than math.

Benjamin Pierce's Types and Programming Languages seems to be the gold
standard of intro type theory, and definitely covers this notation and the
math behind it, in a much more rigorous fashion than PLAI. It is a much deeper
book though, so it doesn't get to type inference and Hindley Milner until
later. I've read some of it and haven't actually gotten this far yet, but can
say that it is a superb textbook, it's very well written and easy for an
amateur to follow, as long as you're relatively comfortable reading and
writing proofs. (but you don't need more math than your standard undergrad
discrete math course)

You might also want to look at Lambda the Ultimate's Getting Started page,
which has a wide range of suggestions covering more than just types, but
programming languages in general.

<http://lambda-the-ultimate.org/node/492>

<http://www.cis.upenn.edu/~bcpierce/tapl/>

[http://cs.brown.edu/~sk/Publications/Books/ProgLangs/2007-04...](http://cs.brown.edu/~sk/Publications/Books/ProgLangs/2007-04-26/)

~~~
profquail
I ported the TAPL code to F# a while back; if you want to check it out:
<https://github.com/jack-pappas/fsharp-tapl>

------
chimeracoder
In reference to the first line of TFA - does anybody know where one could get
that shirt?

~~~
droz
[http://www.cafepress.co.uk/mf/2498088/what-part-of-types-
don...](http://www.cafepress.co.uk/mf/2498088/what-part-of-types-dont-you-
understand_tshirt?shop=skicalc)

------
jheriko
abstract languages like this are merely 'clever' as opposed to useful. it is a
shame that maths and science is polluted by so much of it - it makes otherwise
easy subjects seem alien and difficult

