Skip to content

Commit b1d5760

Browse files
authored
Merge pull request #12841 from dotty-staging/add-polyfun-test
Add the Boehm Berarducci encoding of Lists as a test
2 parents 227d55c + f40da43 commit b1d5760

File tree

2 files changed

+83
-0
lines changed

2 files changed

+83
-0
lines changed

tests/run/boehm-berarducci.check

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
List(1, 2)
2+
List(2)
3+
1
4+
false
5+
List(1, 2)
6+
List(2)
7+
1
8+
false

tests/run/boehm-berarducci.scala

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
/* Boehm-Berarducci encoding of lists in polymorphic typed lambda calculus */
2+
type Op[T, C] = T => C => C
3+
type List[T] = [C] => Op[T, C] => C => C
4+
5+
def nil[T]: List[T] =
6+
[C] => (op: Op[T, C]) => (s: C) => s
7+
8+
def cons[T](hd: T, tl: List[T]): List[T] =
9+
[C] => (op: Op[T, C]) => (s: C) => op(hd)(tl(op)(s))
10+
11+
/** A trait that can be instantiated with a list decomposition `ListView` */
12+
trait ListOps:
13+
type ListView[T]
14+
def decompose[T](xs: List[T]): ListView[T]
15+
def fst[T](v: ListView[T]): T
16+
def snd[T](v: ListView[T]): List[T]
17+
def isPair[T](v: ListView[T]): Boolean
18+
19+
// Some operations and tests that operate with the decomposition
20+
def head[T](xs: List[T]): T = fst(decompose[T](xs))
21+
def tail[T](xs: List[T]): List[T] = snd(decompose[T](xs))
22+
def isEmpty[T](xs: List[T]): Boolean = !isPair(decompose[T](xs))
23+
24+
def toScalaList[T](xs: List[T]): scala.List[T] =
25+
xs[scala.List[T]](h => t => h :: t)(Nil)
26+
27+
def print[T](xs: List[T]): Unit =
28+
println(toScalaList[T](xs))
29+
30+
def test() =
31+
val xs: List[Int] = cons(1, cons(2, nil))
32+
print[Int](xs)
33+
print[Int](tail(xs))
34+
println(head[Int](xs))
35+
println(isEmpty[Int](xs))
36+
end ListOps
37+
38+
// A ListView based on regular Scala classes - options of pairs
39+
object ListOps1 extends ListOps:
40+
type ListView[T] = Option[(T, List[T])]
41+
42+
def push[T](h: T, v: ListView[T]): ListView[T] = v match
43+
case Some((h2, xs2)) => Some(h, cons[T](h2, xs2))
44+
case None => Some(h, nil[T])
45+
46+
def decompose[T](xs: List[T]): ListView[T] =
47+
xs[Option[(T, List[T])]](h => c => push(h, c))(None)
48+
49+
def fst[T](v: ListView[T]): T = v.get._1
50+
def snd[T](v: ListView[T]): List[T] = v.get._2
51+
def isPair[T](v: ListView[T]): Boolean = v.isDefined
52+
53+
// A ListView based on (non-recursive) Church encodings in polymorphic lambda calculus
54+
object ListOps2 extends ListOps:
55+
type ListView[T] = [K] => (T => List[T] => K) => (() => K) => K
56+
57+
def consView[T](x: T, xs: List[T]): ListView[T] =
58+
[K] => (caseCons: T => List[T] => K) => (caseNil: () => K) => caseCons(x)(xs)
59+
60+
def nilView[T]: ListView[T] =
61+
[K] => (caseCons: T => List[T] => K) => (caseNil: () => K) => caseNil()
62+
63+
def push[T](h: T)(c: ListView[T]): ListView[T] =
64+
c[ListView[T]](h2 => xs2 => consView(h, cons[T](h2, xs2)))(() => consView(h, nil[T]))
65+
66+
def decompose[T](xs: List[T]): ListView[T] =
67+
xs[ListView[T]](push)(nilView)
68+
69+
def fst[T](v: ListView[T]): T = v(hd => tl => hd)(() => ???)
70+
def snd[T](v: ListView[T]): List[T] = v(hd => tl => tl)(() => ???)
71+
def isPair[T](v: ListView[T]): Boolean = v(hd => tl => true)(() => false)
72+
73+
@main def Test() =
74+
ListOps1.test()
75+
ListOps2.test()

0 commit comments

Comments
 (0)