Version française
Home     About     Download     Resources     Contact us    
Browse thread
[newbie] Define and use records in sum types
[ Home ] [ Index: by date | by threads ]
[ Search: ]

[ Message by date: previous | next ] [ Message in thread: previous | next ] [ Thread: previous | next ]
Date: -- (:)
From: Markus Mottl <mottl@m...>
Subject: Re: [newbie] Define and use records in sum types
On Fri, 21 Jul 2000, Frank Atanassow wrote:
> Markus Mottl writes:
>  >   module Male = struct
>  >     type t = { name : string; salary : int }
>  >     let raise_salary p n = { p with salary = p.salary + n }
>  >   end
>  > 
>  >   module Female = struct
>  >     type t = { name : string; salary : float }
>  >     let raise_salary p n = { p with salary = p.salary +. n }
>  >   end

> I used to do this. (Actually, in this case I would have used a functor to
> capture the commonality.)

Well, there is not so much commonality to catch in the upper example:
to me, a functor would be a bit overkill here if the only thing you want
to do is having a separate namespace. Unless you really see a longterm
benefit in some abstraction, it's not a good idea to make the code more
complex with functors.

> But I stopped because inevitably, after some development, the type t
> becomes recursive, and you cannot have recursive types spanning modules,
> so I would have to go back to the straightforward method.

Inevitably? Why? At least in the cases where I found a problem with
building modules, I always discovered an easy (and generally much
cleaner) way to restructure the design to get around it. In fact, such
problems point me to design errors. (Yes, there are rare examples, where
redesigning does not help, but I never felt the need to implement one
for real purposes).

> I disagree. In fact, I think one should divorce the type abstraction and
> namespace-handling aspects of modules.

I agree.

> It's true that the uses often coincide,
> but I think it obscures the issues. In particular, I think it encourages
> programmers to conflate syntactic information-hiding (like not exporting some
> constructors or functions) with type-theoretic information-hiding (like
> abstracting a type with a functor). The first ought to be considered only as
> an engineering technique to reduce complexity. The second OTOH is a logical
> technique to increase flexibility of implementation.

But how about "capturing logical invariants"? You need both ways of
information hiding there: restricting the number of exported functions
*and* restricting their types! Otherwise there could be ways to destroy
the invariant.

> As it stands, though, I realize that the current module system is far too
> entrenched to change, so I would be happy if we could just qualify constructor
> and field labels by their type constructor's name, so that this would
> typecheck:
> 
>   type r1 = { name: int }
>   type r2 = { name: float }
>   type t1 = A of int
>   type t2 = A of float
>   let (r2,t2) : r2 * t2 = { name = 1.0 }, A 2.0
>   let (r1,t1) : r1 * t2 = { r1.name = 1 }, t1.A 2

I'd rather use different namings like "r1_name" and "r2_name" for the
field: although this requires me to always include the name of the type,
one cannot get confused either: it makes the sources easier to understand.

Best regards,
Markus Mottl

-- 
Markus Mottl, mottl@miss.wu-wien.ac.at, http://miss.wu-wien.ac.at/~mottl