[TYPES] Issues regarding typeclasses and modular languages like ML
Brian Hulley
brianh at metamilk.com
Wed Apr 8 23:11:46 EDT 2009
Hi,
Although there is some literature on the issue of integrating
Haskell-style typeclasses into modular languages such as ML, it appears
to me that several important issues remain unresolved.
For example, in "Modular Type Classes" [1], the authors model some
aspects of typeclasses by a stylised use of the ML module system,
translating a Haskell class declaration into an ML signature with a
distinguished type component (t), an instance declaration into an ML
structure or functor, and provide a facility to explicitly declare which
structures/functors are to be regarded as "canonical" in any specific
context.
While this is certainly a useful contribution, there are some aspects of
the Haskell typeclass system that do not appear to be amenable to this
treatment. Specifically, their treatment seems (to me) to be only
applicable to those uses of typeclasses where the overloading can be
statically resolved at compile time, rather than the more general case
where one wants to have restricted parametric polymorphism, perhaps in
conjunction with polymorphic recursion and/or existential
quantification, which involves dynamic generation of (or dispatch from)
"dictionary arguments" at runtime, and therefore I do not see how
functor application, which afaict is a strictly compile time activity,
can be used to model this.
Moreover their solution to the coherence problem in the face of multiple
named instances does not appear to deal with the issue of partial
application. This is because they seem to assume that a polymorphic
function can be translated into a suitable functor application that
returns a structure containing a monomorphic value, which is indeed
suggested by the syntax of qualified types in Haskell, but is confounded
by some experimentation with ghci, which shows that dictionary arguments
are actually interspersed with "core" arguments so as to maximize
polymorphism in the face of partial application:
$ ghci -fglasgow-exts -fno-monomorphism-restriction
GHCi, version 6.8.2: http://www.haskell.org/ghc/ :? for help
Loading package base ... linking ... done.
Prelude> let f x y = show y
Prelude> :t f
f :: forall t a. (Show a) => t -> a -> String
Prelude> let g = f 'c'
Prelude> :t g
g :: forall a. (Show a) => a -> String
Prelude> (g 1, g "hi")
("1","\"hi\"")
Prelude>
The salient point in the above example is that the type of (f) in
reality is something like:
Pi (t : *) . Pi (x : t) . Pi (a : * | Show a) . Pi (y : a) . String
so that the dictionary is passed only at the point where we choose how
to instantiate the type variable (a).
Since a partially applied function could be passed as a polymorphic
value to be used anywhere in the program, it seems unlikely that there
is any hope of solving the coherence problem with lexical scoping.
(Aside: two uses of Pi above would usually just be written as arrows but
I find it easier to understand types if everything is written uniformly
in quantifier notation - is there a better quantifier instead of Pi for
this case?)
Of course I am not trying to criticise the above paper in any way, and
many of these issues would not arise in an ML setting at the moment due
to the constraints imposed on the type system by the traditional desire
to continue to support top level HM type inference. It is just that when
one is trying to design a new language, with different tradeoffs (e.g.
discarding TI in favour of first class polymorphism and automatic
type-driven namespace management), one finds that the existing
literature does not yet provide all the answers regarding the
integration of typeclasses with a powerful module system.
Another issue that is problematic concerns the question of identity of a
type, for example:
signature S = sig
type t
val x : t -> int
end
structure M = struct
type t = string
val x = String.toInt
end
structure N = M :> S
In the above, is N.t the same type as M.t or not (as far as any instance
declarations inside M / outside M are concerned)? i.e. if one defines an
instance of some typeclass for M.t would N.t also be a member of the
class via this instance, and if so, would this not imply that
abstraction has been broken?
The problem does not arise in the context of Haskell, since Haskell does
not have any notion of abstract type at all: all types are completely
concrete and the only abstraction facility is to hide the data
constructor(s) so that no inhabitants of the type can be constructed
elsewhere in the program.
I have not been able to find any papers that address the above issue,
since they all seem to just use a pervasive type like (int) or tuples/
lists thereof to illustrate their encoding of typeclasses. The issue
concerns the meaning of "a posteriori" abstraction in ML, and the
literature seems to be divided between merely hiding the relationship
between an abstract type and its implementing type, or actually really
generating a new distinct type (for the latter see [2]). Where does the
notion of instance definition for "*the* type t" fit into this question?
The question *may* be addressed in "ML mit Typklassen" [3] but
unfortunately although the examples are in English the text is in German
and I think I would need more than just a pocket dictionary to try to
follow the arguments therein. Does anyone know of an English
translation, or, if the issue is addressed there, could anyone point me
to the relevant section since with enough time I probably could
translate a few paragraphs.
Apologies for the length of this post. Any pointers to literature or
corrections to my no doubt incomplete understanding would be much
appreciated.
Thanks,
Brian.
[1] "Modular Type Classes" Derek Dreyer, Robert Harper, Manuel M.T.
Chakravarty, Gabriele Keller. 2006/10/26
[2] "Generativity and Dynamic Opacity for Abstract Types (Extended
Version)" Andreas Rossberg. 2003
[3] "ML mit Typklassen" Gerhard Schneider. 4th June 2000.
More information about the Types-list
mailing list