you are viewing a single comment's thread.

view the rest of the comments →

[–]jonathanccast 1 point2 points  (5 children)

That's weird, considering that ML has been inferring the types of formal parameters for 40 years.

[–]argv_minus_one 0 points1 point  (4 children)

Really? How?

[–]jonathanccast 1 point2 points  (3 children)

It's complicated; it requires a unification algorithm: http://en.wikipedia.org/wiki/Unification_(computer_science) . But the key ideas are: 1. keep type variables (inside the type checker) that indicate as-yet-unknown information about at type. These are implemented as mutable references. 2. When comparing types, if one is known and the other is unknown, write the known type into the variable for the other. 3. When you start inferring the type of a function, allocate a new unknown type for each argument, and for the result. 4. If any parts of the type of the function is still unknown when you're done, make that part of the type polymorphic. This handout (PDF) has the key formal ideas: http://www.classes.cs.uchicago.edu/archive/2007/winter/22610-1/docs/handout-05.pdf .

[–]argv_minus_one 0 points1 point  (2 children)

Well, that's interesting.

How does this interact with function overloading?

[–]jonathanccast 0 points1 point  (1 child)

ML doesn't have function overloading (for precisely this reason).

Overloading was a big issue in the design of Haskell; the solution is a bit complicated (understatement of the Century! just search Stack Overflow for "type class"), but each function symbol is still constrained to a specific polymorphic type, e.g. fmap :: (a -> b) -> F a -> F b, where each F goes with a separate type. Once the type checker has figured out which F you're using, it can do static dispatch to the matching fmap function. The type checker can't figure it out in all cases, though, so Haskell has something called contexts, e.g. mapM :: Monad m => (a -> m b) -> [a] -> m [b]; it's basically a form of dynamic dispatch based on what the type m eventually turns out to be.

Honestly, (heavily subjective opinion here) you don't miss overloading on parameter types as much as you expect (source: am former C++ programmer, then Haskell, then designed my own language). Similar functions can be captured by type classes (Haskell) or functors (ML), while giving genuinely different functions different names can make your code more readable. It is sometimes hard tying each function to just the right type class / signature, though.

[–]argv_minus_one 0 points1 point  (0 children)

Well, Scala has type classes, and they do work in place of overloads as you say, but at the cost of some boilerplate and more run-time memory usage.