caml-list - the Caml user's mailing list
 help / color / mirror / Atom feed
From: Roberto Di Cosmo <roberto@dicosmo.org>
To: Leo White <lpw25@cam.ac.uk>
Cc: caml-list@inria.fr
Subject: Re: [Caml-list] Adding Dimensions to types
Date: Fri, 13 Jun 2014 12:12:33 +0200	[thread overview]
Message-ID: <20140613101233.GE18158@traveler> (raw)
In-Reply-To: <868up1kug8.fsf@cam.ac.uk>

Thanks Leo for this answer: basically, following your code,
if I want n dimension, I will need a phantom type with 2*n
variables, and define the units by putting a difference
in the right 'field', right?

It is not really readable, and has limitations, but it
is a nice encoding nonetheless.

On Fri, Jun 13, 2014 at 10:52:23AM +0100, Leo White wrote:
> > Now the question that arose yesterday, and that we could not answer right away, is whether it is possible to encode
> > such dymension checking in OCaml today using only the existing type-system features, so I am passing it over to the
> > list :-)
> 
> You can do something reasonable using difference lists to encode a
> dimension in a phantom type. For example, the following module (based on
> an initial version by Stephen Dolan):
> 
>     module Unit : sig
>       type +'a suc
>       type (+'a, +'b) quantity
> 
>       val of_float : float -> ('a, 'a) quantity
>       val metre : ('a, 'a suc) quantity
>       val mul : ('a, 'b) quantity -> ('b, 'c) quantity -> ('a, 'c) quantity
>       val add : ('a, 'b) quantity -> ('a, 'b) quantity -> ('a, 'b) quantity
>       val neg : ('a, 'b) quantity -> ('a, 'b) quantity
>       val inv : ('a, 'b) quantity -> ('b, 'a) quantity
>     end = struct
>       type 'a suc = unit
>       type ('a, 'b) quantity = float
>       let of_float x = x
>       let metre = 1.
>       let mul x y = x *. y
>       let add x y = x +. y
>       let neg x = 0. -. x
>       let inv x = 1. /. x
>     end
> 
> This successfully tracks the dimension of quatities:
> 
>     # open Unit;;
> 
>     # let m10 = mul (of_float 10.) metre;;
>     val m10 : ('a, 'a Unit.suc) Unit.quantity = <abstr>
> 
>     # let sum = add m10 m10;;
>     val sum : ('a, 'a Unit.suc) Unit.quantity = <abstr>
> 
>     # let sq = mul m10 m10;;
>     val sq : ('a, 'a Unit.suc Unit.suc) Unit.quantity = <abstr>
> 
>     # let cube = mul m10 (mul m10 m10);;
>     val cube : ('a, 'a Unit.suc Unit.suc Unit.suc) Unit.quantity = <abstr>
> 
>     # let _ = add (mul sq (inv cube)) (inv m10);;
>     - : ('a Unit.suc, 'a) Unit.quantity = <abstr>
> 
> and it will give errors if they are used incorrectly:
> 
>     # let _ = add sq cube;;
>     Characters 15-19:
>       let _ = add sq cube;;
>                      ^^^^
>     Error: This expression has type
>              ('a, 'a Unit.suc Unit.suc Unit.suc) Unit.quantity
>            but an expression was expected of type
>              ('a, 'a Unit.suc Unit.suc) Unit.quantity
>            The type variable 'a occurs inside 'a Unit.suc
> 
>     # let _ = add m10 (mul m10 m10);;
>     Characters 16-29:
>       let _ = add m10 (mul m10 m10);;
>                       ^^^^^^^^^^^^^
>     Error: This expression has type ('a, 'a Unit.suc Unit.suc) Unit.quantity
>            but an expression was expected of type ('a, 'a Unit.suc) Unit.quantity
>            The type variable 'a occurs inside 'a Unit.suc
> 
> However, it will infer too restrictive types for some things:
> 
>     # let sq x = mul x x;;
>     val sq : ('a, 'a) Unit.quantity -> ('a, 'a) Unit.quantity = <fun>
> 
> The "real" type of `sq` requires higher-kinded and higher-rank
> polymorphism. Using functors you can encode `sq` thus:
> 
>     # module Sq (X : sig type 'a t end) = struct
>         type arg = {x: 'a. ('a, 'a X.t) quantity}
>         let sq {x} = mul x x
>       end;;
> 
> and apply it like so:
> 
>     # module AppSq = Sq(struct type 'a t = 'a suc end);;
> 
>     # let x = AppSq.sq {AppSq.x = m10};;
>     val x : ('a, 'a Unit.suc Unit.suc) Unit.quantity = <abstr>
> 
> It is also worth noting that -rectypes breaks this encoding:
> 
>     #rectypes;;
> 
>     # let _ = add sq cube;;
>     - : ('a Unit.suc as 'a, 'a Unit.suc Unit.suc) Unit.quantity = <abstr>
> 
> 
> Regards,
> 
> Leo

-- 
Roberto Di Cosmo
 
------------------------------------------------------------------
Professeur               En delegation a l'INRIA
PPS                      E-mail: roberto@dicosmo.org
Universite Paris Diderot WWW  : http://www.dicosmo.org
Case 7014                Tel  : ++33-(0)1-57 27 92 20
5, Rue Thomas Mann       
F-75205 Paris Cedex 13   Identica: http://identi.ca/rdicosmo
FRANCE.                  Twitter: http://twitter.com/rdicosmo
------------------------------------------------------------------
Attachments:
MIME accepted, Word deprecated
      http://www.gnu.org/philosophy/no-word-attachments.html
------------------------------------------------------------------
Office location:
 
Bureau 3020 (3rd floor)
Batiment Sophie Germain
Avenue de France
Metro Bibliotheque Francois Mitterrand, ligne 14/RER C
-----------------------------------------------------------------
GPG fingerprint 2931 20CE 3A5A 5390 98EC 8BFC FCCA C3BE 39CB 12D3                        

  reply	other threads:[~2014-06-13 10:12 UTC|newest]

Thread overview: 10+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2014-06-13  9:10 Roberto Di Cosmo
2014-06-13  9:42 ` David MENTRE
2014-06-13 10:09   ` Roberto Di Cosmo
2014-06-13  9:43 ` Gabriel Scherer
2014-06-13  9:54   ` Roberto Di Cosmo
2014-06-13 12:10     ` Nicolas Boulay
2014-06-13  9:52 ` Leo White
2014-06-13 10:12   ` Roberto Di Cosmo [this message]
2014-06-13 11:06     ` Leo White
2014-06-13 20:08   ` Török Edwin

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20140613101233.GE18158@traveler \
    --to=roberto@dicosmo.org \
    --cc=caml-list@inria.fr \
    --cc=lpw25@cam.ac.uk \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).