Forse finalmente le slide sono finite

main
Antonio De Lucreziis 3 years ago
parent 69e178caa2
commit 1f85bf1425

@ -1,75 +1,60 @@
package main package main
import ( import (
"context"
"fmt" "fmt"
"math/rand"
"time" "time"
) )
func Aggregate[T any](cs ...<-chan T) <-chan T { func trySend[T any](c chan<- T, v T) bool {
agg := make(chan T) select {
case c <- v:
return true
default:
return false
}
}
go func() { func raceSame[T any](cs ...<-chan T) T {
defer close(agg) done := make(chan T)
for { defer close(done)
closed := 0
for _, c := range cs {
select {
case value, more := <-c:
if more {
agg <- value
} else {
closed++
}
default:
}
}
if closed == len(cs) {
break
}
}
}()
return agg for _, c := range cs {
} go func(c <-chan T) {
trySend(done, <-c)
}(c)
}
type TargetChan[T any] struct { return <-done
c <-chan T
target *T
} }
type TryReceiver interface { type Awaiter interface {
TryReceive() bool Await()
} }
func (tc TargetChan[T]) TryReceive() bool { type awaiterChan[T any] <-chan T
select {
case value := <-tc.c: func (rc awaiterChan[T]) Await() { <-rc }
*tc.target = value
return true type targetChan[T any] struct {
default: c <-chan T
return false target *T
}
} }
func AwaitFirst(cancel context.CancelFunc, ws ...TryReceiver) { func (rc targetChan[T]) Await() { *rc.target = <-rc.c }
func raceAny(rs ...Awaiter) {
done := make(chan struct{}) done := make(chan struct{})
go func() { defer close(done)
defer close(done)
for { for _, r := range rs {
for _, w := range ws { go func(r Awaiter) {
if w.TryReceive() { r.Await()
done <- struct{}{} trySend(done, struct{}{})
return }(r)
} }
}
}
}()
<-done <-done
cancel()
return
} }
func main() { func main() {
@ -77,56 +62,30 @@ func main() {
c2 := make(chan int) c2 := make(chan int)
c3 := make(chan float64) c3 := make(chan float64)
c := context.Background()
c, cancel := context.WithCancel(c)
go func() { go func() {
defer close(c1) defer close(c1)
for { time.Sleep(300 * time.Millisecond)
select { c1 <- "1"
case <-c.Done():
return
case <-time.After(300 * time.Millisecond):
}
c1 <- "1"
}
}() }()
go func() { go func() {
defer close(c2) defer close(c2)
for { time.Sleep(400 * time.Millisecond)
select { c2 <- 2
case <-c.Done():
return
case <-time.After(400 * time.Millisecond):
}
c2 <- 2
}
}() }()
go func() { go func() {
defer close(c3) defer close(c3)
for { time.Sleep(200 * time.Millisecond)
select { c3 <- 3.0
case <-c.Done():
return
case <-time.After(200 * time.Millisecond):
}
c3 <- 3.0
}
}() }()
var result1 string
var result2 int var result2 int
var result3 float64 var result3 float64
AwaitFirst( raceAny(
cancel, awaiterChan[string](c1),
TargetChan[string]{c1, &result1}, targetChan[int]{c2, &result2},
TargetChan[int]{c2, &result2}, targetChan[float64]{c3, &result3},
TargetChan[float64]{c3, &result3},
) )
fmt.Println(result1, result2, result3) fmt.Println(result2, result3)
} }

@ -0,0 +1 @@
package main

@ -798,78 +798,109 @@ user1, _ := database.Read(db, tables.Users, userRef1)
<!-- _class: chapter --> <!-- _class: chapter -->
# Altro esempio caotico # Pattern: _Channels_
Vediamo come implementare le _promise_ in Go con le generics Alcune utility per lavorare meglio con i _channel_
--- ---
```go ```go
type Promise[T any] struct { func trySend[T any](c chan<- T, v T) bool {
value T select {
err error case c <- v:
done <-chan struct{} return true
} default:
return false
func (p Promise[T]) Await() (T, error) { }
<-p.done
return p.value, p.err
} }
``` ```
--- ---
```go ```go
type PromiseFunc[T any] func(resolve func(T), reject func(error)) func raceSame[T any](cs ...<-chan T) T {
done := make(chan T)
defer close(done)
for _, c := range cs {
go func(c <-chan T) {
trySend(done, <-c)
}(c)
}
func Run[T any](f PromiseFunc[T]) *Promise[T] { return <-done
done := make(chan struct{}) }
p := Promise{ done: done } ```
go f( ---
func(value T) { p.value = value; done <- struct{} },
func(err error) { p.err = err; done <- struct{} }
)
return &p ```go
type Awaiter interface {
Await()
} }
type awaiterChan[T any] <-chan T
func (rc awaiterChan[T]) Await() { <-rc }
``` ```
--- ---
```go ```go
func AwaitAll[T any](ps ...*Promise[T]) error { type targetChan[T any] struct {
... c <-chan T
target *T
} }
func (rc targetChan[T]) Await() { *rc.target = <-rc.c }
``` ```
---
```go ```go
type Waiter interface { Wait() error } func race(rs ...Awaiter) {
done := make(chan struct{})
defer close(done)
func (p Promise[T]) Wait() error { for _, r := range rs {
<-p.done go func(r Awaiter) {
return p.err r.Await()
} trySend(done, struct{}{})
}(r)
}
func AwaitAll(ws ...Waiter) error { <-done
...
} }
``` ```
--- ---
```go ```go
func ResolveInto[T any](p *Promise[T], target *T) *Promise[T] { var result2 int
... var result3 float64
}
raceAny(
awaiterChan[string](c1),
targetChan[int]{c2, &result2},
targetChan[float64]{c3, &result3},
)
fmt.Println(result2, result3)
``` ```
---
```go ```go
AwaitAll( var result2 int
ResolveInto(httpRequest1, &result1), // :: *Promise[int] var result3 float64
ResolveInto(httpRequest2, &result2), // :: *Promise[struct{ ... }]
ResolveInto(httpRequest3, &result3), // :: *Promise[any] // Variante più pulita di questa utility
timer1, // :: *Promise[struct{}] channels.Race(
channels.Awaiter(c1),
channels.Awaiter(c2, channels.WithTarget(&result2)),
channels.Awaiter(c3, channels.WithTarget(&result3)),
) )
fmt.Println(result2, result3)
``` ```
--- ---
@ -883,15 +914,24 @@ _Proof checking_ in Go
## Premesse ## Premesse
Definiamo i possibili "tipi" delle nostre espressioni
```go ```go
type Bool interface{ isBool() } type Bool interface{ isBool() }
type Term interface{ isTerm() } type Nat interface{ isNat() }
type Term2Term interface{ isTerm2Term() } type Nat2Nat interface{ isNat2Nat() }
```
---
## Premesse
Trick per codificare higher-kinded types in Go
// Trick per codificare higher-kinded types ```go
type V[H Term2Term, T Term] Term type V[ H Nat2Nat, T Nat ] Nat
``` ```
--- ---
@ -899,8 +939,8 @@ type V[H Term2Term, T Term] Term
## Assiomi dei Naturali ## Assiomi dei Naturali
```go ```go
type Zero Term type Zero Nat
type Succ Term2Term type Succ Nat2Nat
// Alcuni alias utili // Alcuni alias utili
type One = V[Succ, Zero] type One = V[Succ, Zero]
@ -918,19 +958,19 @@ type Eq[A, B any] Bool
// Eq_Refl ovvero l'assioma // Eq_Refl ovvero l'assioma
// forall x : x = x // forall x : x = x
func Eq_Reflexive[T any]() Eq[T, T] { func Eq_Reflexive[T any]() Eq[T, T] {
panic("axiom") panic("axiom: comptime only")
} }
// Eq_Symmetric ovvero l'assioma // Eq_Symmetric ovvero l'assioma
// forall a, b: a = b => b = a // forall a, b: a = b => b = a
func Eq_Symmetric[A, B any](_ Eq[A, B]) Eq[B, A] { func Eq_Symmetric[A, B any](_ Eq[A, B]) Eq[B, A] {
panic("axiom") panic("axiom: comptime only")
} }
// Eq_Transitive ovvero l'assioma // Eq_Transitive ovvero l'assioma
// forall a, b, c: a = b e b = c => a = c // forall a, b, c: a = b e b = c => a = c
func Eq_Transitive[A, B, C any](_ Eq[A, B], _ Eq[B, C]) Eq[A, C] { func Eq_Transitive[A, B, C any](_ Eq[A, B], _ Eq[B, C]) Eq[A, C] {
panic("axiom") panic("axiom: comptime only")
} }
``` ```
@ -938,7 +978,7 @@ func Eq_Transitive[A, B, C any](_ Eq[A, B], _ Eq[B, C]) Eq[A, C] {
## Uguaglianza e Sostituzione ## Uguaglianza e Sostituzione
Per ogni funzione `F`, ovvero tipo vincolato all'interfaccia `Term2Term` vorremmo dire che Per ogni funzione `F`, ovvero tipo vincolato all'interfaccia `Nat2Nat` vorremmo dire che
``` ```
F F
@ -954,9 +994,9 @@ Data una funzione ed una dimostrazione che due cose sono uguali allora possiamo
```go ```go
// Function_Eq ovvero l'assioma // Function_Eq ovvero l'assioma
// forall f function, forall a, b term: a = b => f(a) = f(b) // forall f function, forall a, b nat: a = b => f(a) = f(b)
func Function_Eq[F Term2Term, A, B Term](_ Eq[A, B]) Eq[V[F, A], V[F, B]] { func Function_Eq[F Nat2Nat, A, B Nat](_ Eq[A, B]) Eq[V[F, A], V[F, B]] {
panic("axiom") panic("axiom: comptime only")
} }
``` ```
@ -965,24 +1005,24 @@ func Function_Eq[F Term2Term, A, B Term](_ Eq[A, B]) Eq[V[F, A], V[F, B]] {
## Assiomi dell'addizione ## Assiomi dell'addizione
```go ```go
type Plus[L, R Term] Term type Plus[L, R Nat] Nat
// "n + 0 = n" // "n + 0 = n"
// Plus_Zero ovvero l'assioma // Plus_Zero ovvero l'assioma
// forall n, m: n + succ(m) = succ(n + m) // forall n, m: n + succ(m) = succ(n + m)
func Plus_Zero[N Term]() Eq[Plus[N, Zero], N] { func Plus_Zero[N Nat]() Eq[Plus[N, Zero], N] {
panic("axiom") panic("axiom: comptime only")
} }
// "n + (m + 1) = (n + m) + 1" // "n + (m + 1) = (n + m) + 1"
// Plus_Sum ovvero l'assioma // Plus_Sum ovvero l'assioma
// forall a, m: n + succ(m) = succ(n + m) // forall n, m: n + succ(m) = succ(n + m)
func Plus_Sum[N, M Term]() Eq[ func Plus_Sum[N, M Nat]() Eq[
Plus[N, V[Succ, M]], Plus[N, V[Succ, M]],
V[Succ, Plus[N, M]], V[Succ, Plus[N, M]],
] { panic("axiom") } ] { panic("axiom: comptime only") }
``` ```
--- ---

Loading…
Cancel
Save