Warning: this presentation has a degraded style compared to the Beamer/PDF version
Intel
...Intel
they develop their own language, reFLectINRIA
, we develop for them a compiler_+_
instead of ( + )
Int.t
, List.t
... instead of int
, list
... List.t Int.t
, Cons 1 Nil
... One declares it by giving a name and a type:
overload print : IO.output -> α -> unit
overload _+_ : α -> α -> α
One gives the overloaded name and a list of new alternatives.
instance print Int.print Float.print
instance _+_ Int._+_ Float._+_
# let isucc x = 1 + x
- val isucc : Int.t -> Int.t
# let fsucc x = 1.0 + x
- val fsucc : Float.t -> Float.t
# let foo x y = if x = y then x + 12 else y + y
- val foo : Int.t -> Int.t -> Int.t
# false + true
! Unresolved symbol: _+_ : Bool.t -> Bool.t -> Bool.t
! The 2 possible alternatives are:
! Int._+_ : Int.t -> Int.t -> Int.t
! Float._+_ : Float.t -> Float.t -> Float.t
# fun x -> x + x
! Unresolved symbol: _+_ : α -> α -> α
! The 2 possible alternatives are:
! Int._+_ : Int.t -> Int.t -> Int.t
! Float._+_ : Float.t -> Float.t -> Float.t
# let id_int x = x + 0
- val id_int : Int.t -> Int.t
# let id_bool x = x && true
- val id_bool : Bool.t -> Bool.t
# let id_float x = x + 0.0
- val id_float : Float.t -> Float.t
# overload id1 : α -> α
# instance id1 id_int id_bool
# overload id2 : α -> α
# instance id2 id_float id_int
# fun x -> id1 (id2 x)
- <fun> : Int.t -> Int.t
# let inc_fst p = fst p + 1
- val inc_fst : (Int.t * α) -> Int.t
# let inc_snd p = snd p + 1
- val inc_snd : (α * Int.t) -> Int.t
# overload inc_one : (α * β) -> Int.t
# instance inc_one inc_fst inc_snd
! Attempt to overload "inc_one" with alternatives...
! inc_fst : (Int.t * α) -> Int.t
! inc_snd :: (β * Int.t) -> Int.t
Indeed inc_one(42,true)
and inc_one("foo",64)
make sense, but what about inc_one(16,64)
? Int
, Float
are concrete Num
can declare overloaded symbols
let double x = x + x
def
) future_proof
)
> if no candidates and future_proof
then
> raise an overloading error
> else if only one candidate
> and (future_proof
or not def
) then keep it
> else if def
then abstract over its implementation
> else raise an overloading error
When an overloaded symbol cannot be resolved but could be in the future, we abstract the current definition from the implementation of unresolved symbols.
These implicit arguments are then re-introduced at each call site as overloaded occurrences.
# let double x = x + x
- val double : [_+_ : α -> α -> α] => α -> α
In fact the definition of double
implicitly becomes:
let double' _+_ x = x + x
And a call to the function double
is treated like that:
double 42
⇝ double' (_+_ : α -> α -> α) 42
⇝ double' (_+_ : Int.t -> Int.t -> Int.t) 42
⇝ double' Int._+_ 42
f
:
f : [a1 : t1, ..., aN : tN] => t
Add all implicit arguments
f x ⇝ (f' : t1 -> ... -> tN -> t) a1 ... aN x
close_overload _+_
future_proof
extension
We extend the future_proof
predicate to return true when the overloaded symbol is closed
t ::= X | F T1...TN
t antiunif t = t
F t1...tN antiunif F u1...uN = F (t1 antiunif u1)...(tN antiunif uN)
t antiunif u = fresh_var t u
# let rec print_list = ... print ... print_list ...
- val print_list :
- [print : IO.output -> α -> unit] =>
- IO.output -> List.t α -> unit
# overload size : α -> Int.t
# let int_size (_:Int.t) = 1
- val int_size : Int.t -> Int.t
# let pair_size (x, y) = size x + size y
- val pair_size :
- [size : α -> Int.t, size : β -> Int.t]
- => (α * β) -> Int.t
# instance size int_size pair_size
# let
rec
list_size = function
# | [] -> 0
# | x::xs -> size x +
size xs
- val list_size :
- [size : α -> Int.t, size : List.t α -> Int.t]
- => List.t α -> Int.t
list_size xs
- val list_size :
- [size : α -> Int.t]
- => List.t α -> Int.t
# instance size list_size
# size
# list_size size size
# list_size size (list_size size size)
# list_size size (list_size size (list_size ...))
# list_size size
# list_size (pair_size size size)
# list_size (pair_size int_size int_size)
# [(1,2); (3,4)]
# type sequence α = Unit | Seq α (sequence (α * α))
# val seq_size :
# [size : α -> Int.t] => sequence α -> Int.t
# instance size seq_size
# let seq_size = function
# | Unit -> 0
# | Seq x xs -> size x + size xs
- val seq_size : [size : α -> Int.t]
- => sequence α -> Int.t
- val implicit : [size : α -> Int.t]
- => List.t α -> Int.t
# explicit_overloading explicit implicit
- val explicit : (α -> Int.t) -> List.t α -> Int.t
# let print_default oc _ =
# IO.print_string oc "?"
- val print_default : IO.output -> α -> unit
# default_overloading print print_default
T ::= (X, S) | (A, S) | T T
S ::= * | S -> S
# overload map :
# (α -> β) -> **container α -> **container β
# overload bind :
# **container α -> (α -> **container β) -> **container β
# type view **container α =
# Nil | Cons α (**container α)
# type stateM σ **container α =
# State (σ -> **container (α * σ))