1+ // A rewrite of Olivier Blanvillain's [adaptation](https://gist.github.com/OlivierBlanvillain/48bb5c66dbb0557da50465809564ee80)
2+ // of Oleg Kislyov's [lecture notes](http://okmij.org/ftp/tagless-final/course/lecture.pdf)
3+ // on tagless final interpreters.
4+ // Main win: Replace Either by an "algebraic effect" using an implicit function type.
15object Test extends App {
26
37 // Explicit ADT
@@ -12,23 +16,26 @@ object Test extends App {
1216 Add (Lit (8 ), Neg (Add (Lit (1 ), Lit (2 ))))
1317 }
1418
15- // Base algebra
19+ // Base trait for type classes
1620 trait Exp [T ] {
1721 def lit (i : Int ): T
1822 def neg (t : T ): T
1923 def add (l : T , r : T ): T
2024 }
2125
26+ // An example tree
2227 def tf0 [T ] with (e : Exp [T ]): T =
2328 e.add(e.lit(8 ), e.neg(e.add(e.lit(1 ), e.lit(2 ))))
2429
30+ // Typeclass-style Exp syntax
2531 object ExpSyntax {
2632 def lit [T ](i : Int ) with (e : Exp [T ]): T = e.lit(i)
2733 def neg [T ](t : T ) with (e : Exp [T ]): T = e.neg(t)
2834 def add [T ](l : T , r : T ) with (e : Exp [T ]): T = e.add(l, r)
2935 }
3036 import ExpSyntax ._ // It's safe to always have these in scope
3137
38+ // Another tree
3239 def tf1 [T ] with Exp [T ]: T =
3340 add(lit(8 ), neg(add(lit(1 ), lit(2 ))))
3441
@@ -73,7 +80,7 @@ object Test extends App {
7380 println(tfm2[Int ])
7481 println(tfm2[String ])
7582
76- // Added operation: Deserialization
83+ // Added operation: serialization
7784 enum Tree {
7885 case Leaf (s : String )
7986 case Node (s : String , ts : Tree * )
@@ -93,6 +100,8 @@ object Test extends App {
93100 println(s " tf1Tree = $tf1Tree" )
94101 println(s " tfm1Tree = $tfm1Tree" )
95102
103+ // CanThrow infrastructure
104+ // At some point this will be supported in language and stdlib
96105 class CanThrow private ()
97106
98107 object CanThrow {
@@ -122,6 +131,7 @@ object Test extends App {
122131 msg => assert(false , s " thrown: $msg" )
123132 }
124133
134+ // Added operation: deserialization
125135 def readInt (str : String ): Maybe [Int ] =
126136 _try(str.toInt)(_ => _throw(s """ Not a number: " $str" """ ))
127137
@@ -183,6 +193,7 @@ object Test extends App {
183193 assertEquals(fromTree3[String ](tf1[Tree ]), tf1[String ])
184194 assertEquals(fromTree3[String ](tfm1[Tree ]), tfm1[String ])
185195
196+ // Added operation: negation pushdown
186197 enum NCtx { case Pos , Neg }
187198
188199 instance [T ] with (e : Exp [T ]) of Exp [NCtx => T ] {
@@ -232,6 +243,7 @@ object Test extends App {
232243 case Add (l, r) => e.add(finalize[T ](l), finalize[T ](r))
233244 }
234245
246+ // Abstracting over multiple typeclasses
235247 type Ring [T ] = Exp [T ] |=> Mult [T ] |=> T
236248
237249 def tfm1a [T ]: Ring [T ] = add(lit(7 ), neg(mul(lit(1 ), lit(2 ))))
0 commit comments