1// run -gcflags=-G=3 2 3// Copyright 2021 The Go Authors. All rights reserved. 4// Use of this source code is governed by a BSD-style 5// lice 6 7package main 8 9import "fmt" 10 11// Overriding the predeclare "any", so it can be used as a type constraint or a type 12// argument 13type any interface{} 14 15type Function[a, b any] interface { 16 Apply(x a) b 17} 18 19type incr struct{ n int } 20 21func (this incr) Apply(x int) int { 22 return x + this.n 23} 24 25type pos struct{} 26 27func (this pos) Apply(x int) bool { 28 return x > 0 29} 30 31type compose[a, b, c any] struct { 32 f Function[a, b] 33 g Function[b, c] 34} 35 36func (this compose[a, b, c]) Apply(x a) c { 37 return this.g.Apply(this.f.Apply(x)) 38} 39 40type _Eq[a any] interface { 41 Equal(a) bool 42} 43 44type Int int 45 46func (this Int) Equal(that int) bool { 47 return int(this) == that 48} 49 50type List[a any] interface { 51 Match(casenil Function[Nil[a], any], casecons Function[Cons[a], any]) any 52} 53 54type Nil[a any] struct { 55} 56 57func (xs Nil[a]) Match(casenil Function[Nil[a], any], casecons Function[Cons[a], any]) any { 58 return casenil.Apply(xs) 59} 60 61type Cons[a any] struct { 62 Head a 63 Tail List[a] 64} 65 66func (xs Cons[a]) Match(casenil Function[Nil[a], any], casecons Function[Cons[a], any]) any { 67 return casecons.Apply(xs) 68} 69 70type mapNil[a, b any] struct { 71} 72 73func (m mapNil[a, b]) Apply(_ Nil[a]) any { 74 return Nil[b]{} 75} 76 77type mapCons[a, b any] struct { 78 f Function[a, b] 79} 80 81func (m mapCons[a, b]) Apply(xs Cons[a]) any { 82 return Cons[b]{m.f.Apply(xs.Head), Map[a, b](m.f, xs.Tail)} 83} 84 85func Map[a, b any](f Function[a, b], xs List[a]) List[b] { 86 return xs.Match(mapNil[a, b]{}, mapCons[a, b]{f}).(List[b]) 87} 88 89func main() { 90 var xs List[int] = Cons[int]{3, Cons[int]{6, Nil[int]{}}} 91 var ys List[int] = Map[int, int](incr{-5}, xs) 92 var xz List[bool] = Map[int, bool](pos{}, ys) 93 cs1 := xz.(Cons[bool]) 94 cs2 := cs1.Tail.(Cons[bool]) 95 _, ok := cs2.Tail.(Nil[bool]) 96 if cs1.Head != false || cs2.Head != true || !ok { 97 panic(fmt.Sprintf("got %v, %v, %v, expected false, true, true", 98 cs1.Head, cs2.Head, ok)) 99 } 100} 101