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
next prev parent 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