Type Classes, Traits, Implicits...
Bigre !
Frédéric Cabestre
@fcabestre
I'm not a number, I'm a freelance.
Polymorphisme(s)
Inclusion
// C#
interface Shape
{
public double Area { get; }
}
class Square : Shape {
public double Side { get; set; }
public double Area => Side * Side;
}
class Circle : Shape {
public double Radius { get; set; }
public double Area => Radius * Radius * Math.PI;
}
shapes.Aggregate(0d, (acc, shape) => acc + shape.Area);
Polymorphisme(s)
Paramétrique
(* Objective Caml *)
# let rec map f l = match l with
| h :: t -> (f h) :: (map f t)
| nil -> nil
;;
val map : ('a -> 'a) -> 'a list -> 'a list = <fun>
// Java
public class Packet<T extends Serializable> : {
payload : T;
header : Header;
...
}
Polymorphisme(s)
(* Pascal *)
program Adhoc;
function Add(x, y : Integer) : Integer;
begin
Add := x + y
end;
function Add(s, t : String) : String;
begin
Add := Concat(s, t)
end;
begin
Writeln(Add(1, 2));
Writeln(Add('Hello, ', 'Mammals!'));
end.
Première Itération [ C# ]
Polymorphisme Paramétrique
&
Inclusion
Paramétrique + Inclusion
public static class Algorithm<T> where T : Ordered<T>
{
public static List<T> Sort(List<T> source)
{
var result = new List<T>();
foreach (var s in source)
{
var position = result.FindIndex(r => r.gt(s)) switch
{
-1 => result.Count,
int p => p
};
result.Insert(position, s);
}
return result;
}
public static bool Equality(List<T> list1, List<T> list2) =>
list1.Count == list2.Count && list1.Zip(list2).All(p => p.First.eq(p.Second));
}
Paramétrique + Inclusion
public static class Algorithm<T> where T : Ordered<T>
{
public static List<T> Sort(List<T> source)
{
var result = new List<T>();
foreach (var s in source)
{
var position = result.FindIndex(r => r.gt(s)) switch
{
-1 => result.Count,
int p => p
};
result.Insert(position, s);
}
return result;
}
public static bool Equality(List<T> list1, List<T> list2) =>
list1.Count == list2.Count && list1.Zip(list2).All(p => p.First.eq(p.Second));
}
Paramétrique + Inclusion
public static class Algorithm<T> where T : Ordered<T>
{
public static List<T> Sort(List<T> source)
{
var result = new List<T>();
foreach (var s in source)
{
var position = result.FindIndex(r => r.gt(s)) switch
{
-1 => result.Count,
int p => p
};
result.Insert(position, s);
}
return result;
}
public static bool Equality(List<T> list1, List<T> list2) =>
list1.Count == list2.Count && list1.Zip(list2).All(p => p.First.eq(p.Second));
}
Paramétrique + Inclusion
public interface Ordered<in T>
{
bool gt(T that);
bool eq(T that);
}
public class IntOrdered : Ordered<IntOrdered>
{
public int Value { get; set; }
public bool gt(IntOrdered that) => this.Value > that.Value;
public bool eq(IntOrdered that) => this.Value == that.Value;
}
public class StringOrdered : Ordered<StringOrdered>
{
public string Value { get; set; }
public bool gt(StringOrdered that) => string.CompareOrdinal(this.Value, that.Value) > 0;
public bool eq(StringOrdered that) => string.CompareOrdinal(this.Value, that.Value) == 0;
}
Paramétrique + Inclusion
public void IntOrdTest()
{
var intOrds = new List<IntOrdered> {
new() {Value = 1},
new() {Value = -4},
new() {Value = 42},
new() {Value = 12}
};
var actual = Sort(intOrds);
var expected = new List<IntOrdered> {
new() {Value = -4},
new() {Value = 1},
new() {Value = 12},
new() {Value = 42}
};
Assert.IsTrue(Equality(actual, expected));
}
Paramétrique + Inclusion
public void StringOrdTest()
{
var stringOrds = new List<StringOrdered> {
new() {Value = "a"},
new() {Value = "z"},
new() {Value = "e"},
new() {Value = "r"}
};
var actual = Sort(stringOrds);
var expected = new List<StringOrdered> {
new() {Value = "a"},
new() {Value = "e"},
new() {Value = "r"},
new() {Value = "z"}
};
Assert.IsTrue(Equality(actual, expected));
}
Paramétrique + Inclusion
- Liaison Dynamique
- Extension Non Rétroactive
Deuxième Itération [ C# ]
Concept & Modèle
Concept / Modèle
- Concept
expression des exigences que doivent remplir les
paramètres de type d'un algorithme générique
- Modèle
Mise en œuvre d'un concept pour un type donné
Concept / Modèle
public static class Algorithm
{
public static List<T> Sort<T>(List<T> source, Ordered<T> model)
{
var result = new List<T>();
foreach (var s in source)
{
var position = result.FindIndex(r => model.gt(r, s)) switch
{
-1 => result.Count,
int p => p
};
result.Insert(position, s);
}
return result;
}
public static bool Equality<T>(List<T> list1, List<T> list2, Ordered<T> model) =>
list1.Count == list2.Count && list1.Zip(list2).All(p => model.eq(p.First, p.Second));
}
Concept / Modèle
public static class Algorithm
{
public static List<T> Sort<T>(List<T> source, Ordered<T> model)
{
var result = new List<T>();
foreach (var s in source)
{
var position = result.FindIndex(r => model.gt(r, s)) switch
{
-1 => result.Count,
int p => p
};
result.Insert(position, s);
}
return result;
}
public static bool Equality<T>(List<T> list1, List<T> list2, Ordered<T> model) =>
list1.Count == list2.Count && list1.Zip(list2).All(p => model.eq(p.First, p.Second));
}
Concept / Modèle
public static class Algorithm
{
public static List<T> Sort<T>(List<T> source, Ordered<T> model)
{
var result = new List<T>();
foreach (var s in source)
{
var position = result.FindIndex(r => model.gt(r, s)) switch
{
-1 => result.Count,
int p => p
};
result.Insert(position, s);
}
return result;
}
public static bool Equality<T>(List<T> list1, List<T> list2, Ordered<T>) =>
list1.Count == list2.Count && list1.Zip(list2).All(p => model.eq(p.First, p.Second));
}
Concept / Modèle
public interface Ordered<in T>
{
bool gt(T l, T r);
bool eq(T l, T r);
}
public class IntOrdered : Ordered<int>
{
public bool gt(int l, int r) => l > r;
public bool eq(int l, int r) => l == r;
}
Concept / Modèle
public interface Ordered<in T>
{
bool gt(T l, T r);
bool eq(T l, T r);
}
public class IntOrdered : Ordered<int>
{
public bool gt(int l, int r) => l > r;
public bool eq(int l, int r) => l == r;
}
public class StringOrdered : Ordered<string>
{
public bool gt(string l, string r) => string.CompareOrdinal(l, r) > 0;
public bool eq(string l, string r) => string.CompareOrdinal(l, r) == 0;
}
Concept / Modèle
public interface Ordered<in T>
{
bool gt(T l, T r);
bool eq(T l, T r);
}
public class IntOrdered : Ordered<int>
{
public bool gt(int l, int r) => l > r;
public bool eq(int l, int r) => l == r;
}
public class StringOrdered : Ordered<string>
{
public bool gt(string l, string r) => string.CompareOrdinal(l, r) > 0;
public bool eq(string l, string r) => string.CompareOrdinal(l, r) == 0;
}
Concept / Modèle
public class PairOrdered<A , B> : Ordered<(A, B)>
{
public Ordered<A> modelA { get; set; }
public Ordered<B> modelB { get; set; }
public bool gt((A, B) l, (A, B) r) =>
modelA.gt(l.Item1, r.Item1) ||
modelA.eq(l.Item1, r.Item1) && modelB.gt(l.Item2, r.Item2);
public bool eq((A, B) l, (A, B) r) =>
modelA.eq(l.Item1, r.Item1) && modelB.eq(l.Item2, r.Item2);
}
Concept / Modèle
public class PairOrdered<A , B> : Ordered<(A, B)>
{
public Ordered<A> modelA { get; set; }
public Ordered<B> modelB { get; set; }
public bool gt((A, B) l, (A, B) r) =>
modelA.gt(l.Item1, r.Item1) ||
modelA.eq(l.Item1, r.Item1) && modelB.gt(l.Item2, r.Item2);
public bool eq((A, B) l, (A, B) r) =>
modelA.eq(l.Item1, r.Item1) && modelB.eq(l.Item2, r.Item2);
}
Concept / Modèle
public class PairOrdered<A , B> : Ordered<(A, B)>
{
public Ordered<A> modelA { get; set; }
public Ordered<B> modelB { get; set; }
public bool gt((A, B) l, (A, B) r) =>
modelA.gt(l.Item1, r.Item1) ||
modelA.eq(l.Item1, r.Item1) && modelB.gt(l.Item2, r.Item2);
public bool eq((A, B) l, (A, B) r) =>
modelA.eq(l.Item1, r.Item1) && modelB.eq(l.Item2, r.Item2);
}
Concept / Modèle
public void IntOrdTest()
{
var model = new IntOrdered();
var intOrds = new List<int> {1, -4, 42, 12};
var actual = Sort(intOrds, model);
var expected = new List<int> {-4, 1, 12, 42};
Assert.IsTrue(Equality(actual, expected, model));
}
Concept / Modèle
public void IntOrdTest()
{
var model = new IntOrdered();
var intOrds = new List<int> {1, -4, 42, 12};
var actual = Sort(intOrds, model);
var expected = new List<int> {-4, 1, 12, 42};
Assert.IsTrue(Equality(actual, expected, model));
}
Concept / Modèle
public void IntOrdTest()
{
var model = new IntOrdered();
var intOrds = new List<int> {1, -4, 42, 12};
var actual = Sort(intOrds, model);
var expected = new List<int> {-4, 1, 12, 42};
Assert.IsTrue(Equality(actual, expected, model));
}
public void PairOrdTest()
{
var model = new PairOrdered<int, string>() {
modelA = new IntOrdered(),
modelB = new StringOrdered()
};
var pairOrds = new List<(int, string)> {(1, "a"), (-4, "z"), (-4, "e"), (42, "r")};
var actual = Sort(pairOrds, model);
var expected = new List<(int, string)> {(-4, "e"), (-4, "z"), (1, "a"), (42, "r")};
Assert.IsTrue(Equality(actual, expected, model));
}
Concept / Modèle
public void IntOrdTest()
{
var model = new IntOrdered();
var intOrds = new List<int> {1, -4, 42, 12};
var actual = Sort(intOrds, model);
var expected = new List<int> {-4, 1, 12, 42};
Assert.IsTrue(Equality(actual, expected, model));
}
public void PairOrdTest()
{
var model = new PairOrdered<int, string>() {
modelA = new IntOrdered(),
modelB = new StringOrdered()
};
var pairOrds = new List<(int, string)> {(1, "a"), (-4, "z"), (-4, "e"), (42, "r")};
var actual = Sort(pairOrds, model);
var expected = new List<(int, string)> {(-4, "e"), (-4, "z"), (1, "a"), (42, "r")};
Assert.IsTrue(Equality(actual, expected, model));
}
Concept / Modèle
- Extension Rétroactive
- Mise en Œuvre Multiples
- Liaison Dynamique
- Bruit
Troisième Itération [ Scala ]
Arguments Implicites
Poor Man's Type Clases
Poor Man's Type Clases
Arguments Implicites
- Arguments implicites
- Valeurs et définitions implicites
- Conversions implicites
- Classes implicites
Pause
Arguments Implicites
- Arguments implicites
- Valeurs et définitions implicites
- Conversions implicites
- Classes implicites
Arguments Implicites
object Algorithm {
def Sort[T](source: Vector[T], model: Ordered[T]): Vector[T] = {
val result = ArrayBuffer[T]()
for (s <- source) {
val position = result.indexWhere(r => model.gt(r, s)) match {
case -1 => result.length
case p => p
}
result.insert(position, s)
}
result.toVector
}
def Equality[T](vector1 : Vector[T], vector2 : Vector[T], model: Ordered[T]): Boolean =
vector1.length == vector2.length &&
vector1.zip(vector2).forall(p => model.eq(p._1, p._2))
}
Arguments Implicites
object Algorithm {
def Sort[T](source: Vector[T])(implicit model: Ordered[T]): Vector[T] = {
val result = ArrayBuffer[T]()
for (s <- source) {
val position = result.indexWhere(r => model.gt(r, s)) match {
case -1 => result.length
case p => p
}
result.insert(position, s)
}
result.toVector
}
def Equality[T](vector1 : Vector[T], vector2 : Vector[T])(implicit model: Ordered[T]): Boolean =
vector1.length == vector2.length &&
vector1.zip(vector2).forall(p => model.eq(p._1, p._2))
}
Arguments Implicites
object Algorithm {
def Sort[T](source: Vector[T])(implicit model: Ordered[T]): Vector[T] = {
val result = ArrayBuffer[T]()
for (s <- source) {
val position = result.indexWhere(r => model.gt(r, s)) match {
case -1 => result.length
case p => p
}
result.insert(position, s)
}
result.toVector
}
def Equality[T](vector1 : Vector[T], vector2 : Vector[T])(implicit model: Ordered[T]): Boolean =
vector1.length == vector2.length &&
vector1.zip(vector2).forall(p => model.eq(p._1, p._2))
}
Arguments Implicites
object Algorithm {
def Sort[T : Ordered](source: Vector[T]): Vector[T] = {
val result = ArrayBuffer[T]()
for (s <- source) {
val position = result.indexWhere(r => implicitly[Ordered[T]].gt(r, s)) match {
case -1 => result.length
case p => p
}
result.insert(position, s)
}
result.toVector
}
def Equality[T : Ordered](vector1 : Vector[T], vector2 : Vector[T]): Boolean =
vector1.length == vector2.length &&
vector1.zip(vector2).forall(p => implicitly[Ordered[T]].eq(p._1, p._2))
}
Arguments Implicites
object Algorithm {
def Sort[T : Ordered](source: Vector[T]): Vector[T] = {
val result = ArrayBuffer[T]()
for (s <- source) {
val position = result.indexWhere(r => implicitly[Ordered[T]].gt(r, s)) match {
case -1 => result.length
case p => p
}
result.insert(position, s)
}
result.toVector
}
def Equality[T : Ordered](vector1 : Vector[T], vector2 : Vector[T]): Boolean =
vector1.length == vector2.length &&
vector1.zip(vector2).forall(p => implicitly[Ordered[T]].eq(p._1, p._2))
}
Arguments Implicites
object Algorithm {
def Sort[T : Ordered](source: Vector[T]): Vector[T] = {
val result = ArrayBuffer[T]()
for (s <- source) {
val position = result.indexWhere(r => implicitly[Ordered[T]].gt(r, s)) match {
case -1 => result.length
case p => p
}
result.insert(position, s)
}
result.toVector
}
def Equality[T : Ordered](vector1 : Vector[T], vector2 : Vector[T]): Boolean =
vector1.length == vector2.length &&
vector1.zip(vector2).forall(p => implicitly[Ordered[T]].eq(p._1, p._2))
}
Arguments Implicites
sealed trait Ordered[-T] {
def gt(l: T, r: T): Boolean
def eq(l: T, r: T): Boolean
}
object instances {
object IntOrd extends Ordered[Int] {
override def gt(l: Int, r: Int): Boolean = l > r
override def eq(l: Int, r: Int): Boolean = l == r
}
object StringOrd extends Ordered[String] {
override def gt(l: String, r: String): Boolean = l > r
override def eq(l: String, r: String): Boolean = l == r
}
}
Arguments Implicites
sealed trait Ordered[-T] {
def gt(l: T, r: T): Boolean
def eq(l: T, r: T): Boolean
}
object instances {
implicit object IntOrd extends Ordered[Int] {
override def gt(l: Int, r: Int): Boolean = l > r
override def eq(l: Int, r: Int): Boolean = l == r
}
implicit object StringOrd extends Ordered[String] {
override def gt(l: String, r: String): Boolean = l > r
override def eq(l: String, r: String): Boolean = l == r
}
}
Arguments Implicites
sealed trait Ordered[-T] {
def gt(l: T, r: T): Boolean
def eq(l: T, r: T): Boolean
}
object instances {
implicit object IntOrd extends Ordered[Int] {
override def gt(l: Int, r: Int): Boolean = l > r
override def eq(l: Int, r: Int): Boolean = l == r
}
implicit object StringOrd extends Ordered[String] {
override def gt(l: String, r: String): Boolean = l > r
override def eq(l: String, r: String): Boolean = l == r
}
}
Arguments Implicites
object instances {
implicit def PairOrd[A, B](implicit modelA: Ordered[A], modelB: Ordered[B]): Ordered[(A, B)] =
new Ordered[(A, B)] {
override def gt(l: (A, B), r: (A, B)): Boolean =
modelA.gt(l._1, r._1) ||
(modelA.eq(l._1, r._1) && modelB.gt(l._2, r._2))
override def eq(l: (A, B), r: (A, B)): Boolean =
modelA.eq(l._1, r._1) && modelB.eq(l._2, r._2)
}
}
Arguments Implicites
object instances {
implicit def PairOrd[A, B](implicit modelA: Ordered[A], modelB: Ordered[B]): Ordered[(A, B)] =
new Ordered[(A, B)] {
override def gt(l: (A, B), r: (A, B)): Boolean =
modelA.gt(l._1, r._1) ||
(modelA.eq(l._1, r._1) && modelB.gt(l._2, r._2))
override def eq(l: (A, B), r: (A, B)): Boolean =
modelA.eq(l._1, r._1) && modelB.eq(l._2, r._2)
}
}
Arguments Implicites
object instances {
implicit def PairOrd[A, B](implicit modelA: Ordered[A], modelB: Ordered[B]): Ordered[(A, B)] =
new Ordered[(A, B)] {
override def gt(l: (A, B), r: (A, B)): Boolean =
modelA.gt(l._1, r._1) ||
(modelA.eq(l._1, r._1) && modelB.gt(l._2, r._2))
override def eq(l: (A, B), r: (A, B)): Boolean =
modelA.eq(l._1, r._1) && modelB.eq(l._2, r._2)
}
}
Arguments Implicites
test("StringOrd Test") {
import net.sigusr.implicit1.instances.StringOrd
val stringOrds = Vector("a", "z", "e", "r")
val actual = Sort(stringOrds)
val expected = Vector("a", "e", "r", "z")
assert(Algorithm.Equality(actual, expected))
}
Arguments Implicites
test("StringOrd Test") {
import net.sigusr.implicit1.instances.StringOrd
val stringOrds = Vector("a", "z", "e", "r")
val actual = Sort(stringOrds)
val expected = Vector("a", "e", "r", "z")
assert(Algorithm.Equality(actual, expected))
}
test("PairOrd Test") {
import net.sigusr.implicit1.instances.{IntOrd, PairOrd, StringOrd}
val pairOrds = Vector((1, "a"), (-4, "z"), (-4, "e"), (42, "r"))
val actual = Sort(pairOrds)
val expected = Vector((-4, "e"), (-4, "z"), (1, "a"), (42, "r"))
assert(Algorithm.Equality(actual, expected))
}
Arguments Implicites
test("StringOrd Test") {
import net.sigusr.implicit1.instances.StringOrd
val stringOrds = Vector("a", "z", "e", "r")
val actual = Sort(stringOrds)
val expected = Vector("a", "e", "r", "z")
assert(Algorithm.Equality(actual, expected))
}
test("PairOrd Test") {
import net.sigusr.implicit1.instances.{IntOrd, PairOrd, StringOrd}
val pairOrds = Vector((1, "a"), (-4, "z"), (-4, "e"), (42, "r"))
val actual = Sort(pairOrds)
val expected = Vector((-4, "e"), (-4, "z"), (1, "a"), (42, "r"))
assert(Algorithm.Equality(actual, expected))
}
Arguments Implicites
- Moins de Bruit
- Type Classes Idiomatiques
- Type Classes Idiomatiques
- Complexe... Parce que Magique ?
Haskell
insert :: Ordered a => a -> [a] -> [a]
insert elem [] = [elem]
insert elem (h:t) = if gt elem h then h:(insert elem t) else elem:h:t
sort :: Ordered a => [a] -> [a]
sort = foldr insert []
Haskell
insert :: Ordered a => a -> [a] -> [a]
insert elem [] = [elem]
insert elem (h:t) = if gt elem h then h:(insert elem t) else elem:h:t
sort :: Ordered a => [a] -> [a]
sort = foldr insert []
Haskell
class Ordered a where
gt :: a -> a -> Bool
eq :: a -> a -> Bool
Haskell
class Ordered a where
gt :: a -> a -> Bool
eq :: a -> a -> Bool
instance Ordered Integer where
gt r l = r > l
eq r l = r == l
instance Ordered String where
gt r l = r > l
eq r l = r == l
Haskell
class Ordered a where
gt :: a -> a -> Bool
eq :: a -> a -> Bool
instance Ordered Integer where
gt r l = r > l
eq r l = r == l
instance Ordered String where
gt r l = r > l
eq r l = r == l
instance (Ordered a, Ordered b) => Ordered (a, b) where
gt (r1, r2) (l1, l2) = gt r1 l1 || (eq r1 l1 && gt r2 l2)
eq (r1, r2) (l1, l2) = eq r1 l1 && eq r2 l2
Haskell
class Ordered a where
gt :: a -> a -> Bool
eq :: a -> a -> Bool
instance Ordered Integer where
gt r l = r > l
eq r l = r == l
instance Ordered String where
gt r l = r > l
eq r l = r == l
instance (Ordered a, Ordered b) => Ordered (a, b) where
gt (r1, r2) (l1, l2) = gt r1 l1 || (eq r1 l1 && gt r2 l2)
eq (r1, r2) (l1, l2) = eq r1 l1 && eq r2 l2
Haskell
Loaded GHCi configuration from /tmp/haskell-stack-ghci/a76106fb/ghci-script
*Ordered Algorithm Ordered> sort [(1, "a"), (-4, "z"), (-4, "e"), (42, "r")]
[(-4,"e"),(-4,"z"),(1,"a"),(42,"r")]
*Ordered Algorithm Ordered>
Haskell
- Traduction λ-calcul Second Ordre
- Passage Dictionnaire
- Construction du Langage
- Complexe... Parce que Magique ?
Rust
pub fn sort<T: Ordered + Clone>(source: &Vec<T>) -> Vec<T> {
let mut result: Vec<T> = Vec::new();
for s in source {
let position =
match result.iter().position(|r| Ordered::gt(r, &s)) {
None => result.len(),
Some(p) => p
};
result.insert(position, s.clone());
}
return result;
}
pub fn equality<T: Ordered>(vector1: &Vec<T>, vector2: &Vec<T>) -> bool {
vector1.len() ==
vector2.len() &&
vector1.iter()
.zip(vector2.iter())
.all(|p| Ordered::eq(p.0, p.1))
}
Rust
pub fn sort<T: Ordered + Clone>(source: &Vec<T>) -> Vec<T> {
let mut result: Vec<T> = Vec::new();
for s in source {
let position =
match result.iter().position(|r| Ordered::gt(r, &s)) {
None => result.len(),
Some(p) => p
};
result.insert(position, s.clone());
}
return result;
}
pub fn equality<T: Ordered>(vector1: &Vec<T>, vector2: &Vec<T>) -> bool {
vector1.len() ==
vector2.len() &&
vector1.iter()
.zip(vector2.iter())
.all(|p| Ordered::eq(p.0, p.1))
}
Rust
pub fn sort<T: Ordered + Clone>(source: &Vec<T>) -> Vec<T> {
let mut result: Vec<T> = Vec::new();
for s in source {
let position =
match result.iter().position(|r| Ordered::gt(r, &s)) {
None => result.len(),
Some(p) => p
};
result.insert(position, s.clone());
}
return result;
}
pub fn equality<T: Ordered>(vector1: &Vec<T>, vector2: &Vec<T>) -> bool {
vector1.len() ==
vector2.len() &&
vector1.iter()
.zip(vector2.iter())
.all(|p| Ordered::eq(p.0, p.1))
}
Rust
pub trait Ordered {
fn gt(l: &Self, r: &Self) -> bool;
fn eq(l: &Self, r: &Self) -> bool;
}
impl Ordered for i32 {
fn gt(l: &Self, r: &Self) -> bool { return l > r; }
fn eq(l: &Self, r: &Self) -> bool { return l == r; }
}
impl Ordered for &str {
fn gt(l: &Self, r: &Self) -> bool { return str::gt(*l, *r); }
fn eq(l: &Self, r: &Self) -> bool { return str::eq(*l, *r); }
}
Rust
pub trait Ordered {
fn gt(l: &Self, r: &Self) -> bool;
fn eq(l: &Self, r: &Self) -> bool;
}
impl Ordered for i32 {
fn gt(l: &Self, r: &Self) -> bool { return l > r; }
fn eq(l: &Self, r: &Self) -> bool { return l == r; }
}
impl Ordered for &str {
fn gt(l: &Self, r: &Self) -> bool { return str::gt(*l, *r); }
fn eq(l: &Self, r: &Self) -> bool { return str::eq(*l, *r); }
}
Rust
impl<A: Ordered, B: Ordered> Ordered for (A, B) {
fn gt(l: &Self, r: &Self) -> bool {
A::gt(&l.0, &r.0) || (A::eq(&l.0, &r.0) && B::gt(&l.1, &r.1))
}
fn eq(l: &Self, r: &Self) -> bool {
A::eq(&l.0, &r.0) && B::eq(&l.1, &r.1)
}
}
Rust
impl<A: Ordered, B: Ordered> Ordered for (A, B) {
fn gt(l: &Self, r: &Self) -> bool {
A::gt(&l.0, &r.0) || (A::eq(&l.0, &r.0) && B::gt(&l.1, &r.1))
}
fn eq(l: &Self, r: &Self) -> bool {
A::eq(&l.0, &r.0) && B::eq(&l.1, &r.1)
}
}
Rust
#[test]
fn string_ord_test() {
use crate::algorithm::sort;
let string_ords = vec!("a", "z", "e", "r");
let actual = sort(&string_ords);
let expected = vec!("a", "e", "r", "z");
assert!(equality(&actual, &expected))
}
#[test]
fn pair_ord_test() {
use crate::algorithm::sort;
let pair_ords = vec!((1, "a"), (-4, "z"), (-4, "e"), (42, "r"));
let actual = sort(&pair_ords);
let expected = vec!((-4, "e"), (-4, "z"), (1, "a"), (42, "r"));
assert!(equality(&actual, &expected))
}
Rust
- Monomorphisation
- Construction du Langage
- Extension rétroactive ?
Rust
use std::hash::{Hash, Hasher};
use guid_create::GUID;
impl Hash for GUID {
fn hash<H: Hasher>(&self, state: &mut H) {
state.write_u32(self.0.data1());
state.write_u16(self.0.data2());
state.write_u16(self.0.data3());
for b in self.0.data4().iter() {
state.write_u8(*b)
}
}
Rust
use std::hash::{Hash, Hasher};
use guid_create::GUID;
impl Hash for GUID {
fn hash<H: Hasher>(&self, state: &mut H) {
state.write_u32(self.0.data1());
state.write_u16(self.0.data2());
state.write_u16(self.0.data3());
for b in self.0.data4().iter() {
state.write_u8(*b)
}
}
Rust
Rust
❝ Only traits defined in the current crate
can be implemented for arbitrary types ❞
Rust
use guid_create::GUID;
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub struct HGuid(GUID);
impl HGuid {
pub fn new() -> HGuid {
HGuid(GUID::rand())
}
}
Rust
use std::hash::{Hash, Hasher};
impl Hash for HGuid {
fn hash<H: Hasher>(&self, state: &mut H) {
state.write_u32(self.0.data1());
state.write_u16(self.0.data2());
state.write_u16(self.0.data3());
for b in self.0.data4().iter() {
state.write_u8(*b)
}
}
}
Ressources
- How to make ad-hoc polymorphism less ad hoc [PDF]
- Type Classes as Objects and Implicits [PDF]
- Implementing Haskell Overloading [PDF]
- Implementing, and Understanding Type Classes [BLOG]
- Code de cette présentation [CODE]
Frédéric Cabestre
@fcabestre
Merci