caml-list - the Caml user's mailing list
 help / color / mirror / Atom feed
From: Leo White <lpw25@cam.ac.uk>
To: Roberto Di Cosmo <roberto@dicosmo.org>
Cc: caml-list@inria.fr
Subject: Re: [Caml-list] Adding Dimensions to types
Date: Fri, 13 Jun 2014 10:52:23 +0100	[thread overview]
Message-ID: <868up1kug8.fsf@cam.ac.uk> (raw)
In-Reply-To: <CAJBwKuWZHefK-_hD7TdOxKFK8YFU06NXjn2UZSgu6O_5aXVcHQ@mail.gmail.com> (Roberto Di Cosmo's message of "Fri, 13 Jun 2014 11:10:24 +0200")

> 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

  parent reply	other threads:[~2014-06-13  9:52 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 [this message]
2014-06-13 10:12   ` Roberto Di Cosmo
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=868up1kug8.fsf@cam.ac.uk \
    --to=lpw25@cam.ac.uk \
    --cc=caml-list@inria.fr \
    --cc=roberto@dicosmo.org \
    /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).