| // run | |
| // Copyright 2021 The Go Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style | |
| // license that can be found in the LICENSE file. | |
| package main | |
| import "fmt" | |
| // Overriding the predeclare "any", so it can be used as a type constraint or a type | |
| // argument | |
| type any interface{} | |
| type Function[a, b any] interface { | |
| Apply(x a) b | |
| } | |
| type incr struct{ n int } | |
| func (this incr) Apply(x int) int { | |
| return x + this.n | |
| } | |
| type pos struct{} | |
| func (this pos) Apply(x int) bool { | |
| return x > 0 | |
| } | |
| type compose[a, b, c any] struct { | |
| f Function[a, b] | |
| g Function[b, c] | |
| } | |
| func (this compose[a, b, c]) Apply(x a) c { | |
| return this.g.Apply(this.f.Apply(x)) | |
| } | |
| type _Eq[a any] interface { | |
| Equal(a) bool | |
| } | |
| type Int int | |
| func (this Int) Equal(that int) bool { | |
| return int(this) == that | |
| } | |
| type List[a any] interface { | |
| Match(casenil Function[Nil[a], any], casecons Function[Cons[a], any]) any | |
| } | |
| type Nil[a any] struct { | |
| } | |
| func (xs Nil[a]) Match(casenil Function[Nil[a], any], casecons Function[Cons[a], any]) any { | |
| return casenil.Apply(xs) | |
| } | |
| type Cons[a any] struct { | |
| Head a | |
| Tail List[a] | |
| } | |
| func (xs Cons[a]) Match(casenil Function[Nil[a], any], casecons Function[Cons[a], any]) any { | |
| return casecons.Apply(xs) | |
| } | |
| type mapNil[a, b any] struct { | |
| } | |
| func (m mapNil[a, b]) Apply(_ Nil[a]) any { | |
| return Nil[b]{} | |
| } | |
| type mapCons[a, b any] struct { | |
| f Function[a, b] | |
| } | |
| func (m mapCons[a, b]) Apply(xs Cons[a]) any { | |
| return Cons[b]{m.f.Apply(xs.Head), Map[a, b](m.f, xs.Tail)} | |
| } | |
| func Map[a, b any](f Function[a, b], xs List[a]) List[b] { | |
| return xs.Match(mapNil[a, b]{}, mapCons[a, b]{f}).(List[b]) | |
| } | |
| func main() { | |
| var xs List[int] = Cons[int]{3, Cons[int]{6, Nil[int]{}}} | |
| var ys List[int] = Map[int, int](incr{-5}, xs) | |
| var xz List[bool] = Map[int, bool](pos{}, ys) | |
| cs1 := xz.(Cons[bool]) | |
| cs2 := cs1.Tail.(Cons[bool]) | |
| _, ok := cs2.Tail.(Nil[bool]) | |
| if cs1.Head != false || cs2.Head != true || !ok { | |
| panic(fmt.Sprintf("got %v, %v, %v, expected false, true, true", | |
| cs1.Head, cs2.Head, ok)) | |
| } | |
| } |