31  Exercise: Programming with Encapsulated Effects

\(\newcommand{\TirName}[1]{\text{#1}} \newcommand{\inferrule}[3][]{ \let\and\qquad \begin{array}{@{}l@{}} \TirName{#1} \\ \displaystyle \frac{#2}{#3} \end{array} } \newcommand{\infer}[3][]{\inferrule[#1]{#2}{#3}} \)

Learning Goals

The primary learning goal of this exercise is to get experience programming with encapsulated effects.

We will also consider the idea of transforming code represented as an abstract syntax tree to make it easier to implement subsequent passes like interpretation.

Instructions

This assignment asks you to write Scala code. There are restrictions associated with how you can solve these problems. Please pay careful heed to those. If you are unsure, ask the course staff.

Note that ??? indicates that there is a missing function or code fragment that needs to be filled in. Make sure that you remove the ??? and replace it with the answer.

Use the test cases provided to test your implementations. You are also encouraged to write your own test cases to help debug your work. However, please delete any extra cells you may have created lest they break an autograder.

Imports

org.scalatest._
// Run this cell FIRST before testing.
import $ivy.`org.scalatest::scalatest:3.2.19`, org.scalatest._, events._, flatspec._, matchers.should._
import $ivy.`org.scalatestplus::scalacheck-1-18:3.2.19.0`, org.scalatestplus.scalacheck._
def report(suite: Suite): Unit = suite.execute(stats = true)
def assertPassed(suite: Suite): Unit =
  suite.run(None, Args(new Reporter {
    def apply(e: Event) = e match {
      case e @ (_: TestFailed) => assert(false, s"${e.message} (${e.testName})")
      case _ => ()
    }
  }))
def passed(points: Int): Unit = {
  require(points >= 0)
  if (points == 1) println("*** ๐ŸŽ‰ Tests Passed (1 point) ***")
  else println(s"*** ๐ŸŽ‰ Tests Passed ($points points) ***")
}
def test(suite: Suite, points: Int): Unit = {
  report(suite)
  assertPassed(suite)
  passed(points)
}
import $ivy.$                                , org.scalatest._, events._, flatspec._, matchers.should._
import $ivy.$                                            , org.scalatestplus.scalacheck._
defined function report
defined function assertPassed
defined function passed
defined function test

31.1 TypeScripty: Numbers, Booleans, and Functions

31.1.1 Syntax

In this assignment, we consider a simplified TypeScripty with numbers, booleans, and functions types.

Function literals \(x\texttt{(}y\texttt{:}\,\tau\texttt{)}\texttt{:}\,\tau' \mathrel{\texttt{=}\!\texttt{>}} e_1\) have exactly one parameter, are always named, and must have a return type annotation. The name may be used to define recursive functions.

The expressions include variable uses \(x\), variable binding \(\mathbf{const}\;x\;\texttt{=}\;e_1\texttt{;}\;e_2\), unary \(\mathop{\mathit{uop}} e_1\) and binary \(e_1 \mathbin{\mathit{bop}} e_2\) expressions, if-then-else \(e_1\;\texttt{?}\;e_2\;\texttt{:}\;e_3\), and function call \(e_1\texttt{(}e_2\texttt{)}\). The unary operators are limited to number negation \(\texttt{-}\) and boolean negation \(\texttt{!}\), and the binary operators are limited to number addition \(\texttt{+}\), number times \(\texttt{*}\), and equality \(\texttt{===}\):

\[ \begin{array}{rrrl} \text{types} & \tau& \mathrel{::=}& \texttt{number} \mid\texttt{bool} \mid\texttt{(}y\texttt{:}\,\tau\texttt{)} \mathrel{\texttt{=}\!\texttt{>}} \tau' \\ \text{values} & v& \mathrel{::=}& n \mid b \mid x\texttt{(}y\texttt{:}\,\tau\texttt{)}\texttt{:}\,\tau' \mathrel{\texttt{=}\!\texttt{>}} e_1 \\ \text{expressions} & e& \mathrel{::=}& x \mid\mathbf{const}\;x\;\texttt{=}\;e_1\texttt{;}\;e_2 \\ & & \mid& n \mid\mathop{\mathit{uop}} e_1 \mid e_1 \mathbin{\mathit{bop}} e_2 \\ & & \mid& b \mid e_1\;\texttt{?}\;e_2\;\texttt{:}\;e_3 \\ & & \mid& x\texttt{(}y\texttt{:}\,\tau\texttt{)}\texttt{:}\,\tau' \mathrel{\texttt{=}\!\texttt{>}} e_1 \mid e_1\texttt{(}e_2\texttt{)} \\ \text{unary operators} & \mathit{uop}& \mathrel{::=}& \texttt{-}\mid\texttt{!} \\ \text{binary operators} & \mathit{bop}& \mathrel{::=}& \texttt{+}\mid\texttt{*}\mid\texttt{===} \end{array} \]

Figure 31.1: Syntax of TypeScripty with recursive functions and limited arithmetic-logical expressions.

We give a Scala representation of the abstract syntax, along with an implementation of computing the free variables of an expression and determining an expression is closed:

trait Typ                                                // t
case object TNumber extends Typ                          // t ::= number
case object TBool extends Typ                            // t ::= bool
case class TFun(yt: (String,Typ), tret: Typ) extends Typ // t ::= (y: t) => tret

trait Expr                                                       // e
case class Var(x: String) extends Expr                           // e ::= x
case class ConstDecl(x: String, e1: Expr, e2: Expr) extends Expr // e ::= const x = e1; e2

case class N(n: Double) extends Expr                         // e ::= n
case class Unary(uop: Uop, e1: Expr) extends Expr            // e ::= uop e1
case class Binary(bop: Bop, e1: Expr, e2: Expr) extends Expr // e ::= e1 bop b2

case class B(b: Boolean) extends Expr                    // e ::= b
case class If(e1: Expr, e2: Expr, e3: Expr) extends Expr // e ::= e1 ? e2 : e3

case class Fun(x: String, yt: (String, Typ), tret: Typ, e1: Expr) extends Expr // e ::= x(y: t): tret => e1
case class Call(e1: Expr, e2: Expr) extends Expr                               // e ::= e1(e2)

trait Uop                   // uop
case object Neg extends Uop // uop ::= -
case object Not extends Uop // uop ::= !

trait Bop                     // bop
case object Plus extends Bop  // bop ::= *
case object Times extends Bop // bop ::= *
case object Eq extends Bop    // bop ::= ===

def freeVars(e: Expr): Set[String] = e match {
  case Var(x) => Set(x)
  case ConstDecl(x, e1, e2) => freeVars(e1) | (freeVars(e2) - x)
  case N(_) | B(_) => Set.empty
  case Unary(_, e1) => freeVars(e1)
  case Binary(_, e1, e2) => freeVars(e1) | freeVars(e2)
  case If(e1, e2, e3) => freeVars(e1) | freeVars(e2) | freeVars(e3)
  case Fun(x, (y, _), _, e1) => freeVars(e1) - x - y
  case Call(e1, e2) => freeVars(e1) | freeVars(e2)
}

def isClosed(e: Expr): Boolean = freeVars(e).isEmpty
defined trait Typ
defined object TNumber
defined object TBool
defined class TFun
defined trait Expr
defined class Var
defined class ConstDecl
defined class N
defined class Unary
defined class Binary
defined class B
defined class If
defined class Fun
defined class Call
defined trait Uop
defined object Neg
defined object Not
defined trait Bop
defined object Plus
defined object Times
defined object Eq
defined function freeVars
defined function isClosed

31.1.2 Static Type Checking

The typing judgment \(\Gamma \vdash e : \tau\) says, โ€œIn typing environment \(\Gamma\), expression \(e\) has type \(\tau\)โ€ where the typing environment \(\Gamma\mathrel{::=}\cdot\mid\Gamma, x : \tau\) is a finite map from variables to types, assigning types to the free variables of \(e\). We give the expected typing rules that we have seen before, restricted to this simpler language:

\(\fbox{$\Gamma \vdash e : \tau$}\)

\(\inferrule[TypeVar]{ }{ \Gamma \vdash x : \Gamma(x) }\)

\(\inferrule[TypeConstDecl]{ \Gamma \vdash e_1 : \tau_1 \and \Gamma, x : \tau_1 \vdash e_2 : \tau_2 }{ \Gamma \vdash \mathbf{const}\;x\;\texttt{=}\;e_1\texttt{;}\;e_2 : \tau_2 }\)

\(\inferrule[TypeNumber]{ }{ \Gamma \vdash n : \texttt{number} }\)

\(\inferrule[TypeNeg]{ \Gamma \vdash e_1 : \texttt{number} }{ \Gamma \vdash \mathop{\texttt{-}} e_1 : \texttt{number} }\)

\(\inferrule[TypeArith]{ \Gamma \vdash e_1 : \texttt{number} \and \Gamma \vdash e_2 : \texttt{number} \and \mathit{bop}\in \left\{ \texttt{+}, \texttt{*} \right\} }{ \Gamma \vdash e_1 \mathbin{\mathit{bop}}e_2 : \texttt{number} }\)

\(\inferrule[TypeBool]{ }{ \Gamma \vdash b : \texttt{bool} }\)

\(\inferrule[TypeEq]{ \Gamma \vdash e_1 : \tau \and \Gamma \vdash e_2 : \tau }{ \Gamma \vdash e_1 \mathbin{\texttt{===}} e_2 : \texttt{bool} }\)

\(\inferrule[TypeIf]{ \Gamma \vdash e_1 : \texttt{bool} \and \Gamma \vdash e_2 : \tau \and \Gamma \vdash e_3 : \tau }{ \Gamma \vdash e_1\;\texttt{?}\;e_2\;\texttt{:}\;e_3 : \tau }\)

\(\inferrule[TypeFunctionRec]{ \Gamma, x : \texttt{(}y\texttt{:}\,\tau\texttt{)} \mathrel{\texttt{=}\!\texttt{>}} \tau' , y : \tau \vdash e' : \tau' }{ \Gamma \vdash x\texttt{(}y\texttt{:}\,\tau\texttt{)}\texttt{:}\,\tau' \mathrel{\texttt{=}\!\texttt{>}} e' : \texttt{(}y\texttt{:}\,\tau\texttt{)} \mathrel{\texttt{=}\!\texttt{>}} \tau' }\)

\(\inferrule[TypeCall]{ \Gamma \vdash e_1 : \texttt{(}y\texttt{:}\,\tau\texttt{)} \mathrel{\texttt{=}\!\texttt{>}} \tau' \and \Gamma \vdash e_2 : \tau }{ \Gamma \vdash e_1\texttt{(}e_2\texttt{)} : \tau' }\)

Figure 31.2: Typing of TypeScripty with recursive functions and limited arithmetic-logical expressions.

31.2 Error Effects

As we have seen, the most direct way to implement a type checker following the typing judgment \(\Gamma \vdash e : \tau\) is a function hastype: (Map[String, Typ], Expr) => Typ that takes an typing environment \(\Gamma\) represented by a Map[String, Typ] and an expression \(e\) represented by a Expr and returns a type \(\tau\) represented by a Typ:

def hastype(tenv: Map[String, Typ], e: Expr): Typ = ???

However, with this function signature for hastype, we necessarily have to throw an exception or crash to indicate that an expression \(e\) is ill-typed. An expression is ill-typed when there are no rules that allow us to derive a judgment \(\Gamma \vdash e : \tau\) for any \(\tau\) and \(\Gamma\).

In this exercise, we implement a version of hastype that makes explicit the possibility of a type error.

31.2.1 Type-Error Result

We first extend our typing judgment form \(\Gamma \vdash e : r\) where a type-checker result \(r\) is either a type \(\tau\) or a type-error result \(\mathit{typerr}\):

type-checker result \(\quad r \mathrel{::=} \mathit{typerr} \mid \tau\)

type-error result \(\quad \mathit{typerr} \mathrel{::=} \mathop{\mathsf{typerr}}(e : \tau)\)

This extended judgment form makes explicit when an expression is ill-typed. A type-error result

\[ \mathop{\mathsf{typerr}}(e : \tau) \]

includes an expression \(e\) with its inferred type \(\tau\) but is used in a context another type is expected. We can consider such a type-error result being used to give a descriptive error message to the programmer.

We now give some rules that introduce type-error results and propagates them:

\(\fbox{$\Gamma \vdash e : r$}\)

\(\inferrule[TypeErrorNeg]{ \Gamma \vdash e_1 : \tau_1 \and \tau_1 \neq \texttt{number} }{ \Gamma \vdash \mathop{\texttt{-}} e_1 : \mathop{\mathsf{typerr}}(e_1 : \tau_1) }\)

\(\inferrule[PropagateNeg]{ \Gamma \vdash e_1 : \mathit{typerr} }{ \Gamma \vdash \mathop{\texttt{-}} e_1 : \mathit{typerr} }\)

\(\inferrule[TypeErrorEq]{ \Gamma \vdash e_1 : \tau_1 \and \Gamma \vdash e_2 : \tau_2 \and \tau_1 \neq \tau_2 }{ \Gamma \vdash e_1 \mathbin{\texttt{===}} e_2 : \mathop{\mathsf{typerr}}(e_2 : \tau_2) }\)

\(\inferrule[PropagateEq1]{ \Gamma \vdash e_1 : \mathit{typerr} }{ \Gamma \vdash e_1 \mathbin{\texttt{===}} e_2 : \mathit{typerr} }\)

\(\inferrule[PropagateEq2]{ \Gamma \vdash e_2 : \mathit{typerr} }{ \Gamma \vdash e_1 \mathbin{\texttt{===}} e_2 : \mathit{typerr} }\)

Observe that the \(\TirName{TypeErrorEq}\) blames \(e_2\): it infers the type \(\tau_1\) for \(e_1\) and then expects that \(e_2\) has type \(\tau_1\).

Exercise 31.1 (4 points) Define the \(\TirName{TypeErrorNot}\) rule that introduces a type-error result when the boolean negation expression \(\mathop{\texttt{!}} e_1\) is ill-typed:

Edit this cell:

???

Notes

  • Hint: Use \(\TirName{TypeErrorNeg}\) as a model.
  • You may give the rule in LaTeX math or as plain text (ascii art) approximating the math rendering. For example,
TypeErrorNeg
Gamma |- e1 : tau1  tau1 != number
------------------------------------------
Gamma |- -e1 : typerr(e1 : tau1 != number)

The LaTeX code for the rendered \(\TirName{TypeErrorNeg}\) rule above is as follows:

\inferrule[TypeErrorNeg]{
  \Gamma \vdash e_1 : \tau_1
  \and
  \tau_1 \neq \texttt{number}
}{
  \Gamma \vdash \mathop{\texttt{-}} e_1 :  \mathop{\mathsf{typerr}}(e_1 : \tau_1 \neq \texttt{number})
}

Exercise 31.2 (8 points) Define two \(\TirName{TypeErrorIf}\) rules that introduces a type-error result when the if-then-else expression \(e_1\;\texttt{?}\;e_2\;\texttt{:}\;e_3\) is ill-typed:

Edit this cell:

???

Notes

  • Hint: Use \(\TirName{TypeErrorNeg}\) and \(\TirName{TypeErrorEq}\) as a model for the two rules, respectively.

31.2.2 Implementation

We represent a type-error result \(r\) as an Either[StaticTypeError, Typ].

Exercise 31.3 (26 points) Complete the following implementation of

hastype: (Map[String, Typ], Expr) => Either[StaticTypeError, Typ]

corresponding to the judgment form \(\Gamma \vdash e : r\).

Edit this cell:

case class StaticTypeError(tbad: Typ, esub: Expr, e: Expr) {
  override def toString = s"StaticTypeError: invalid type $tbad for sub-expression $esub in $e"
}

def hastype(tenv: Map[String, Typ], e: Expr): Either[StaticTypeError, Typ] = {

  def err[T](esub: Expr, tgot: Typ): Either[StaticTypeError, T] =
    Left(StaticTypeError(tgot, esub, e))

  def typecheck(tenv: Map[String, Typ], e: Expr, tshould: Typ): Either[StaticTypeError, Unit] =
    hastype(tenv, e) flatMap { tgot =>
      if (tgot == tshould)
        ???
      else err(e, tgot)
    }

  e match {
    case Var(x) => Right(tenv(x))
    case ConstDecl(x, e1, e2) =>
      ???
    case N(_) => Right(TNumber)
    case B(_) => Right(TBool)
    case Unary(Neg, e1) => typecheck(tenv, e1, TNumber) map { _ => TNumber }
    case Unary(Not, e1) =>
      ???
    case Binary(Plus|Times, e1, e2) =>
      ???
    case Binary(Eq, e1, e2) =>
      hastype(tenv, e1) flatMap { t1 =>
        hastype(tenv, e2) flatMap { t2 =>
          if (t1 == t2) Right(TBool) else err(e2, t2)
        }
      }
    case If(e1, e2, e3) => typecheck(tenv, e1, TBool) flatMap { _ =>
      ???
    }
    case Fun(x, yt @ (y, t), tret, e1) => {
      ???
    }
    case Call(e1, e2) =>
      ???
  }
}

def inferType(e: Expr): Either[StaticTypeError, Typ] = {
  require(isClosed(e), s"$e should be closed")
  hastype(Map.empty, e)
}
defined class StaticTypeError
defined function hastype
defined function inferType

Notes

  • The err helper function is simply a shortcut to construct StaticTypeError with the input expression e.
  • The typecheck helper function implements a common functionality where we want to call hastype recursively with a sub-expression to infer a type tgot and check it is equal to an expected type tshould. If tgot != tshould, we return an err; otherwise, we return success.
  • Hint: Start by implementing the \(\TirName{Type}\) rules from Figure 31.2 without worrying about type errors. Then, add \(\TirName{TypeError}\) and \(\TirName{Propagate}\) cases.
  • Note that not all the \(\TirName{TypeError}\) and \(\TirName{Propagate}\) rules are given, but they follow the patterns given above. If you get stuck to implement the code for \(\TirName{TypeError}\) for a particular construct, try writing out the rule.
  • It is fine to initially pattern match on Either[StaticTypeError, Expr] values that result from calls to hastype and typecheck (i.e., for Left and Right values). However, challenge yourself to replace them with map or flatMap calls to minimize your typing and opportunities for bugs to creep in. It is possible to replace all pattern matches for Left and Right values with calls to map and flatMap calls.
  • Use the given cases (e.g., \(\TirName{TypeNeg}\), \(\TirName{TypeErrorNeg}\), \(\TirName{PropagateNeg}\)) as a model. Identify how \(\TirName{TypeNeg}\), \(\TirName{TypeErrorNeg}\), and \(\TirName{PropagateNeg}\) manifests in the code.
  • For accelerated students, you can make the code even more compact (and arguably more readable) by replacing flatMap and map calls with for-yield expressions. Note that not all cases can be implemented with for-yield expressions.

Tests

test(new AnyFlatSpec {
  val e1 = Binary(Plus, N(1), N(2)) 
  val e2 = Binary(Times, Var("a"), N(3))

  val e3 = ConstDecl("a", e1, e2)
  "hastype/ConstDecl" should "TypeConstDecl" in {
    assertResult(Right(TNumber)) {inferType(e1) }
  }

  val badesub = B(true)
  val bade = Binary(Plus, N(1), badesub)
  it should "PropagateConstDecl1" in {
    assertResult(Left(StaticTypeError(TBool, badesub, bade))) { inferType(ConstDecl("a", bade, N(1))) }
  }

  it should "PropagateConstDecl2" in {
    assertResult(Left(StaticTypeError(TBool, badesub, bade))) { inferType(ConstDecl("a", N(1), bade)) }
  }
}, 4)
Run starting. Expected test count is: 3
cmd3$Helper$$anon$1:
hastype/ConstDecl
- should TypeConstDecl *** FAILED ***
  scala.NotImplementedError: an implementation is missing
  at scala.Predef$.$qmark$qmark$qmark(Predef.scala:345)
  at ammonite.$sess.cmd2$Helper.hastype(cmd2.sc:27)
  at ammonite.$sess.cmd2$Helper.inferType(cmd2.sc:47)
  at ammonite.$sess.cmd3$Helper$$anon$1.$anonfun$new$1(cmd3.sc:7)
  at org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85)
  at org.scalatest.OutcomeOf.outcomeOf$(OutcomeOf.scala:83)
  at org.scalatest.OutcomeOf$.outcomeOf(OutcomeOf.scala:104)
  at org.scalatest.Transformer.apply(Transformer.scala:22)
  at org.scalatest.Transformer.apply(Transformer.scala:20)
  at org.scalatest.flatspec.AnyFlatSpecLike$$anon$5.apply(AnyFlatSpecLike.scala:1832)
  ...
- should PropagateConstDecl1 *** FAILED ***
  scala.NotImplementedError: an implementation is missing
  at scala.Predef$.$qmark$qmark$qmark(Predef.scala:345)
  at ammonite.$sess.cmd2$Helper.hastype(cmd2.sc:20)
  at ammonite.$sess.cmd2$Helper.inferType(cmd2.sc:47)
  at ammonite.$sess.cmd3$Helper$$anon$1.$anonfun$new$2(cmd3.sc:13)
  at org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85)
  at org.scalatest.OutcomeOf.outcomeOf$(OutcomeOf.scala:83)
  at org.scalatest.OutcomeOf$.outcomeOf(OutcomeOf.scala:104)
  at org.scalatest.Transformer.apply(Transformer.scala:22)
  at org.scalatest.Transformer.apply(Transformer.scala:20)
  at org.scalatest.flatspec.AnyFlatSpecLike$$anon$5.apply(AnyFlatSpecLike.scala:1832)
  ...
- should PropagateConstDecl2 *** FAILED ***
  scala.NotImplementedError: an implementation is missing
  at scala.Predef$.$qmark$qmark$qmark(Predef.scala:345)
  at ammonite.$sess.cmd2$Helper.hastype(cmd2.sc:20)
  at ammonite.$sess.cmd2$Helper.inferType(cmd2.sc:47)
  at ammonite.$sess.cmd3$Helper$$anon$1.$anonfun$new$3(cmd3.sc:17)
  at org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85)
  at org.scalatest.OutcomeOf.outcomeOf$(OutcomeOf.scala:83)
  at org.scalatest.OutcomeOf$.outcomeOf(OutcomeOf.scala:104)
  at org.scalatest.Transformer.apply(Transformer.scala:22)
  at org.scalatest.Transformer.apply(Transformer.scala:20)
  at org.scalatest.flatspec.AnyFlatSpecLike$$anon$5.apply(AnyFlatSpecLike.scala:1832)
  ...
Run completed in 75 milliseconds.
Total number of tests run: 3
Suites: completed 1, aborted 0
Tests: succeeded 0, failed 3, canceled 0, ignored 0, pending 0
*** 3 TESTS FAILED ***
java.lang.AssertionError: assertion failed: an implementation is missing (hastype/ConstDecl should TypeConstDecl)
  scala.Predef$.assert(Predef.scala:280)
  ammonite.$sess.cmd0$Helper$$anon$1.apply(cmd0.sc:7)
  org.scalatest.WrapperCatchReporter.doApply(CatchReporter.scala:70)
  org.scalatest.CatchReporter.apply(CatchReporter.scala:36)
  org.scalatest.CatchReporter.apply$(CatchReporter.scala:34)
  org.scalatest.WrapperCatchReporter.apply(CatchReporter.scala:63)
  org.scalatest.Suite$.reportTestFailed(Suite.scala:1644)
  org.scalatest.SuperEngine.runTestImpl(Engine.scala:347)
  org.scalatest.flatspec.AnyFlatSpecLike.runTest(AnyFlatSpecLike.scala:1842)
  org.scalatest.flatspec.AnyFlatSpecLike.runTest$(AnyFlatSpecLike.scala:1824)
  org.scalatest.flatspec.AnyFlatSpec.runTest(AnyFlatSpec.scala:1686)
  org.scalatest.flatspec.AnyFlatSpecLike.$anonfun$runTests$1(AnyFlatSpecLike.scala:1900)
  org.scalatest.SuperEngine.$anonfun$runTestsInBranch$1(Engine.scala:413)
  scala.collection.immutable.List.foreach(List.scala:333)
  org.scalatest.SuperEngine.traverseSubNodes$1(Engine.scala:401)
  org.scalatest.SuperEngine.runTestsInBranch(Engine.scala:390)
  org.scalatest.SuperEngine.$anonfun$runTestsInBranch$1(Engine.scala:427)
  scala.collection.immutable.List.foreach(List.scala:333)
  org.scalatest.SuperEngine.traverseSubNodes$1(Engine.scala:401)
  org.scalatest.SuperEngine.runTestsInBranch(Engine.scala:396)
  org.scalatest.SuperEngine.runTestsImpl(Engine.scala:475)
  org.scalatest.flatspec.AnyFlatSpecLike.runTests(AnyFlatSpecLike.scala:1900)
  org.scalatest.flatspec.AnyFlatSpecLike.runTests$(AnyFlatSpecLike.scala:1899)
  org.scalatest.flatspec.AnyFlatSpec.runTests(AnyFlatSpec.scala:1686)
  org.scalatest.Suite.run(Suite.scala:1114)
  org.scalatest.Suite.run$(Suite.scala:1096)
  org.scalatest.flatspec.AnyFlatSpec.org$scalatest$flatspec$AnyFlatSpecLike$$super$run(AnyFlatSpec.scala:1686)
  org.scalatest.flatspec.AnyFlatSpecLike.$anonfun$run$1(AnyFlatSpecLike.scala:1945)
  org.scalatest.SuperEngine.runImpl(Engine.scala:535)
  org.scalatest.flatspec.AnyFlatSpecLike.run(AnyFlatSpecLike.scala:1945)
  org.scalatest.flatspec.AnyFlatSpecLike.run$(AnyFlatSpecLike.scala:1943)
  org.scalatest.flatspec.AnyFlatSpec.run(AnyFlatSpec.scala:1686)
  ammonite.$sess.cmd0$Helper.assertPassed(cmd0.sc:5)
  ammonite.$sess.cmd0$Helper.test(cmd0.sc:18)
  ammonite.$sess.cmd3$Helper.<init>(cmd3.sc:19)
  ammonite.$sess.cmd3$.<clinit>(cmd3.sc:7)
test(new AnyFlatSpec {
  val e1 = Unary(Not, B(true))
  "hastype/Unary/Not" should "TypeNot" in {
    assertResult(Right(TBool)) {inferType(e1) }
  }

  val e2 = Unary(Not, N(1))
  it should "TypeErrorNot" in {
    assertResult(Left(StaticTypeError(TNumber, N(1), e2))) {inferType(e2) }
  }

  val badesub = B(true)
  val bade = Binary(Plus, N(1), badesub)
  it should "PropagateNot" in {
    assertResult(Left(StaticTypeError(TBool, badesub, bade))) { inferType(Unary(Not, bade)) }
  }
}, 4)
Run starting. Expected test count is: 3
cmd4$Helper$$anon$1:
hastype/Unary/Not
- should TypeNot *** FAILED ***
  scala.NotImplementedError: an implementation is missing
  at scala.Predef$.$qmark$qmark$qmark(Predef.scala:345)
  at ammonite.$sess.cmd2$Helper.hastype(cmd2.sc:25)
  at ammonite.$sess.cmd2$Helper.inferType(cmd2.sc:47)
  at ammonite.$sess.cmd4$Helper$$anon$1.$anonfun$new$1(cmd4.sc:4)
  at org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85)
  at org.scalatest.OutcomeOf.outcomeOf$(OutcomeOf.scala:83)
  at org.scalatest.OutcomeOf$.outcomeOf(OutcomeOf.scala:104)
  at org.scalatest.Transformer.apply(Transformer.scala:22)
  at org.scalatest.Transformer.apply(Transformer.scala:20)
  at org.scalatest.flatspec.AnyFlatSpecLike$$anon$5.apply(AnyFlatSpecLike.scala:1832)
  ...
- should TypeErrorNot *** FAILED ***
  scala.NotImplementedError: an implementation is missing
  at scala.Predef$.$qmark$qmark$qmark(Predef.scala:345)
  at ammonite.$sess.cmd2$Helper.hastype(cmd2.sc:25)
  at ammonite.$sess.cmd2$Helper.inferType(cmd2.sc:47)
  at ammonite.$sess.cmd4$Helper$$anon$1.$anonfun$new$2(cmd4.sc:9)
  at org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85)
  at org.scalatest.OutcomeOf.outcomeOf$(OutcomeOf.scala:83)
  at org.scalatest.OutcomeOf$.outcomeOf(OutcomeOf.scala:104)
  at org.scalatest.Transformer.apply(Transformer.scala:22)
  at org.scalatest.Transformer.apply(Transformer.scala:20)
  at org.scalatest.flatspec.AnyFlatSpecLike$$anon$5.apply(AnyFlatSpecLike.scala:1832)
  ...
- should PropagateNot *** FAILED ***
  scala.NotImplementedError: an implementation is missing
  at scala.Predef$.$qmark$qmark$qmark(Predef.scala:345)
  at ammonite.$sess.cmd2$Helper.hastype(cmd2.sc:25)
  at ammonite.$sess.cmd2$Helper.inferType(cmd2.sc:47)
  at ammonite.$sess.cmd4$Helper$$anon$1.$anonfun$new$3(cmd4.sc:15)
  at org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85)
  at org.scalatest.OutcomeOf.outcomeOf$(OutcomeOf.scala:83)
  at org.scalatest.OutcomeOf$.outcomeOf(OutcomeOf.scala:104)
  at org.scalatest.Transformer.apply(Transformer.scala:22)
  at org.scalatest.Transformer.apply(Transformer.scala:20)
  at org.scalatest.flatspec.AnyFlatSpecLike$$anon$5.apply(AnyFlatSpecLike.scala:1832)
  ...
Run completed in 3 milliseconds.
Total number of tests run: 3
Suites: completed 1, aborted 0
Tests: succeeded 0, failed 3, canceled 0, ignored 0, pending 0
*** 3 TESTS FAILED ***
java.lang.AssertionError: assertion failed: an implementation is missing (hastype/Unary/Not should TypeNot)
  scala.Predef$.assert(Predef.scala:280)
  ammonite.$sess.cmd0$Helper$$anon$1.apply(cmd0.sc:7)
  org.scalatest.WrapperCatchReporter.doApply(CatchReporter.scala:70)
  org.scalatest.CatchReporter.apply(CatchReporter.scala:36)
  org.scalatest.CatchReporter.apply$(CatchReporter.scala:34)
  org.scalatest.WrapperCatchReporter.apply(CatchReporter.scala:63)
  org.scalatest.Suite$.reportTestFailed(Suite.scala:1644)
  org.scalatest.SuperEngine.runTestImpl(Engine.scala:347)
  org.scalatest.flatspec.AnyFlatSpecLike.runTest(AnyFlatSpecLike.scala:1842)
  org.scalatest.flatspec.AnyFlatSpecLike.runTest$(AnyFlatSpecLike.scala:1824)
  org.scalatest.flatspec.AnyFlatSpec.runTest(AnyFlatSpec.scala:1686)
  org.scalatest.flatspec.AnyFlatSpecLike.$anonfun$runTests$1(AnyFlatSpecLike.scala:1900)
  org.scalatest.SuperEngine.$anonfun$runTestsInBranch$1(Engine.scala:413)
  scala.collection.immutable.List.foreach(List.scala:333)
  org.scalatest.SuperEngine.traverseSubNodes$1(Engine.scala:401)
  org.scalatest.SuperEngine.runTestsInBranch(Engine.scala:390)
  org.scalatest.SuperEngine.$anonfun$runTestsInBranch$1(Engine.scala:427)
  scala.collection.immutable.List.foreach(List.scala:333)
  org.scalatest.SuperEngine.traverseSubNodes$1(Engine.scala:401)
  org.scalatest.SuperEngine.runTestsInBranch(Engine.scala:396)
  org.scalatest.SuperEngine.runTestsImpl(Engine.scala:475)
  org.scalatest.flatspec.AnyFlatSpecLike.runTests(AnyFlatSpecLike.scala:1900)
  org.scalatest.flatspec.AnyFlatSpecLike.runTests$(AnyFlatSpecLike.scala:1899)
  org.scalatest.flatspec.AnyFlatSpec.runTests(AnyFlatSpec.scala:1686)
  org.scalatest.Suite.run(Suite.scala:1114)
  org.scalatest.Suite.run$(Suite.scala:1096)
  org.scalatest.flatspec.AnyFlatSpec.org$scalatest$flatspec$AnyFlatSpecLike$$super$run(AnyFlatSpec.scala:1686)
  org.scalatest.flatspec.AnyFlatSpecLike.$anonfun$run$1(AnyFlatSpecLike.scala:1945)
  org.scalatest.SuperEngine.runImpl(Engine.scala:535)
  org.scalatest.flatspec.AnyFlatSpecLike.run(AnyFlatSpecLike.scala:1945)
  org.scalatest.flatspec.AnyFlatSpecLike.run$(AnyFlatSpecLike.scala:1943)
  org.scalatest.flatspec.AnyFlatSpec.run(AnyFlatSpec.scala:1686)
  ammonite.$sess.cmd0$Helper.assertPassed(cmd0.sc:5)
  ammonite.$sess.cmd0$Helper.test(cmd0.sc:18)
  ammonite.$sess.cmd4$Helper.<init>(cmd4.sc:17)
  ammonite.$sess.cmd4$.<clinit>(cmd4.sc:7)
test(new AnyFlatSpec {
  val e1 = Binary(Plus, N(1), N(2))
  "hastype/Binary/Plus|Times" should "TypeArith" in {
    assertResult(Right(TNumber)) { inferType( Binary(Times, e1, N(2)) ) }
  }

  val e2 = Binary(Plus, B(true), e1)
  it should "TypeErrorArith" in {
    assertResult(Left(StaticTypeError(TBool, B(true), e2))) { inferType(e2) }
  }

  val badesub = B(true)
  val bade = Binary(Plus, N(1), badesub)
  it should "PropagateArith" in {
    assertResult(Left(StaticTypeError(TBool, badesub, bade))) { inferType(Binary(Plus, bade, N(3))) }
  }
}, 4)
Run starting. Expected test count is: 3
cmd5$Helper$$anon$1:
hastype/Binary/Plus|Times
- should TypeArith *** FAILED ***
  scala.NotImplementedError: an implementation is missing
  at scala.Predef$.$qmark$qmark$qmark(Predef.scala:345)
  at ammonite.$sess.cmd2$Helper.hastype(cmd2.sc:27)
  at ammonite.$sess.cmd2$Helper.inferType(cmd2.sc:47)
  at ammonite.$sess.cmd5$Helper$$anon$1.$anonfun$new$1(cmd5.sc:4)
  at org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85)
  at org.scalatest.OutcomeOf.outcomeOf$(OutcomeOf.scala:83)
  at org.scalatest.OutcomeOf$.outcomeOf(OutcomeOf.scala:104)
  at org.scalatest.Transformer.apply(Transformer.scala:22)
  at org.scalatest.Transformer.apply(Transformer.scala:20)
  at org.scalatest.flatspec.AnyFlatSpecLike$$anon$5.apply(AnyFlatSpecLike.scala:1832)
  ...
- should TypeErrorArith *** FAILED ***
  scala.NotImplementedError: an implementation is missing
  at scala.Predef$.$qmark$qmark$qmark(Predef.scala:345)
  at ammonite.$sess.cmd2$Helper.hastype(cmd2.sc:27)
  at ammonite.$sess.cmd2$Helper.inferType(cmd2.sc:47)
  at ammonite.$sess.cmd5$Helper$$anon$1.$anonfun$new$2(cmd5.sc:9)
  at org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85)
  at org.scalatest.OutcomeOf.outcomeOf$(OutcomeOf.scala:83)
  at org.scalatest.OutcomeOf$.outcomeOf(OutcomeOf.scala:104)
  at org.scalatest.Transformer.apply(Transformer.scala:22)
  at org.scalatest.Transformer.apply(Transformer.scala:20)
  at org.scalatest.flatspec.AnyFlatSpecLike$$anon$5.apply(AnyFlatSpecLike.scala:1832)
  ...
- should PropagateArith *** FAILED ***
  scala.NotImplementedError: an implementation is missing
  at scala.Predef$.$qmark$qmark$qmark(Predef.scala:345)
  at ammonite.$sess.cmd2$Helper.hastype(cmd2.sc:27)
  at ammonite.$sess.cmd2$Helper.inferType(cmd2.sc:47)
  at ammonite.$sess.cmd5$Helper$$anon$1.$anonfun$new$3(cmd5.sc:15)
  at org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85)
  at org.scalatest.OutcomeOf.outcomeOf$(OutcomeOf.scala:83)
  at org.scalatest.OutcomeOf$.outcomeOf(OutcomeOf.scala:104)
  at org.scalatest.Transformer.apply(Transformer.scala:22)
  at org.scalatest.Transformer.apply(Transformer.scala:20)
  at org.scalatest.flatspec.AnyFlatSpecLike$$anon$5.apply(AnyFlatSpecLike.scala:1832)
  ...
Run completed in 1 millisecond.
Total number of tests run: 3
Suites: completed 1, aborted 0
Tests: succeeded 0, failed 3, canceled 0, ignored 0, pending 0
*** 3 TESTS FAILED ***
java.lang.AssertionError: assertion failed: an implementation is missing (hastype/Binary/Plus|Times should TypeArith)
  scala.Predef$.assert(Predef.scala:280)
  ammonite.$sess.cmd0$Helper$$anon$1.apply(cmd0.sc:7)
  org.scalatest.WrapperCatchReporter.doApply(CatchReporter.scala:70)
  org.scalatest.CatchReporter.apply(CatchReporter.scala:36)
  org.scalatest.CatchReporter.apply$(CatchReporter.scala:34)
  org.scalatest.WrapperCatchReporter.apply(CatchReporter.scala:63)
  org.scalatest.Suite$.reportTestFailed(Suite.scala:1644)
  org.scalatest.SuperEngine.runTestImpl(Engine.scala:347)
  org.scalatest.flatspec.AnyFlatSpecLike.runTest(AnyFlatSpecLike.scala:1842)
  org.scalatest.flatspec.AnyFlatSpecLike.runTest$(AnyFlatSpecLike.scala:1824)
  org.scalatest.flatspec.AnyFlatSpec.runTest(AnyFlatSpec.scala:1686)
  org.scalatest.flatspec.AnyFlatSpecLike.$anonfun$runTests$1(AnyFlatSpecLike.scala:1900)
  org.scalatest.SuperEngine.$anonfun$runTestsInBranch$1(Engine.scala:413)
  scala.collection.immutable.List.foreach(List.scala:333)
  org.scalatest.SuperEngine.traverseSubNodes$1(Engine.scala:401)
  org.scalatest.SuperEngine.runTestsInBranch(Engine.scala:390)
  org.scalatest.SuperEngine.$anonfun$runTestsInBranch$1(Engine.scala:427)
  scala.collection.immutable.List.foreach(List.scala:333)
  org.scalatest.SuperEngine.traverseSubNodes$1(Engine.scala:401)
  org.scalatest.SuperEngine.runTestsInBranch(Engine.scala:396)
  org.scalatest.SuperEngine.runTestsImpl(Engine.scala:475)
  org.scalatest.flatspec.AnyFlatSpecLike.runTests(AnyFlatSpecLike.scala:1900)
  org.scalatest.flatspec.AnyFlatSpecLike.runTests$(AnyFlatSpecLike.scala:1899)
  org.scalatest.flatspec.AnyFlatSpec.runTests(AnyFlatSpec.scala:1686)
  org.scalatest.Suite.run(Suite.scala:1114)
  org.scalatest.Suite.run$(Suite.scala:1096)
  org.scalatest.flatspec.AnyFlatSpec.org$scalatest$flatspec$AnyFlatSpecLike$$super$run(AnyFlatSpec.scala:1686)
  org.scalatest.flatspec.AnyFlatSpecLike.$anonfun$run$1(AnyFlatSpecLike.scala:1945)
  org.scalatest.SuperEngine.runImpl(Engine.scala:535)
  org.scalatest.flatspec.AnyFlatSpecLike.run(AnyFlatSpecLike.scala:1945)
  org.scalatest.flatspec.AnyFlatSpecLike.run$(AnyFlatSpecLike.scala:1943)
  org.scalatest.flatspec.AnyFlatSpec.run(AnyFlatSpec.scala:1686)
  ammonite.$sess.cmd0$Helper.assertPassed(cmd0.sc:5)
  ammonite.$sess.cmd0$Helper.test(cmd0.sc:18)
  ammonite.$sess.cmd5$Helper.<init>(cmd5.sc:17)
  ammonite.$sess.cmd5$.<clinit>(cmd5.sc:7)
test(new AnyFlatSpec {
  val e1 = Binary(Plus, N(1), N(2))
  "hastype/If" should "TypeIf" in {
    assertResult(Right(TNumber)) { inferType( If(B(true), e1, N(3)) ) }
  }

  val e2 = If(N(1), e1, e1)
  it should "TypeErrorIfGuard" in {
    assertResult(Left(StaticTypeError(TNumber, N(1), e2))) { inferType(e2) }
  }

  val e3 = If(B(false), B(true), N(1))
  it should "TypeErrorIfBody" in {
    assertResult(Left(StaticTypeError(TNumber, N(1), e3))) { inferType(e3) }
  }

  val badesub = B(true)
  val bade = Binary(Plus, N(1), badesub)
  it should "PropagateIf" in {
    assertResult(Left(StaticTypeError(TBool, badesub, bade))) { inferType(If(B(true), bade, N(3))) }
  }
}, 4)
Run starting. Expected test count is: 4
cmd6$Helper$$anon$1:
hastype/If
- should TypeIf *** FAILED ***
  scala.NotImplementedError: an implementation is missing
  at scala.Predef$.$qmark$qmark$qmark(Predef.scala:345)
  at ammonite.$sess.cmd2$Helper.$anonfun$hastype$1(cmd2.sc:13)
  at scala.util.Either.flatMap(Either.scala:352)
  at ammonite.$sess.cmd2$Helper.typecheck$1(cmd2.sc:11)
  at ammonite.$sess.cmd2$Helper.hastype(cmd2.sc:34)
  at ammonite.$sess.cmd2$Helper.inferType(cmd2.sc:47)
  at ammonite.$sess.cmd6$Helper$$anon$1.$anonfun$new$1(cmd6.sc:4)
  at org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85)
  at org.scalatest.OutcomeOf.outcomeOf$(OutcomeOf.scala:83)
  at org.scalatest.OutcomeOf$.outcomeOf(OutcomeOf.scala:104)
  ...
- should TypeErrorIfGuard
- should TypeErrorIfBody *** FAILED ***
  scala.NotImplementedError: an implementation is missing
  at scala.Predef$.$qmark$qmark$qmark(Predef.scala:345)
  at ammonite.$sess.cmd2$Helper.$anonfun$hastype$1(cmd2.sc:13)
  at scala.util.Either.flatMap(Either.scala:352)
  at ammonite.$sess.cmd2$Helper.typecheck$1(cmd2.sc:11)
  at ammonite.$sess.cmd2$Helper.hastype(cmd2.sc:34)
  at ammonite.$sess.cmd2$Helper.inferType(cmd2.sc:47)
  at ammonite.$sess.cmd6$Helper$$anon$1.$anonfun$new$3(cmd6.sc:14)
  at org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85)
  at org.scalatest.OutcomeOf.outcomeOf$(OutcomeOf.scala:83)
  at org.scalatest.OutcomeOf$.outcomeOf(OutcomeOf.scala:104)
  ...
- should PropagateIf *** FAILED ***
  scala.NotImplementedError: an implementation is missing
  at scala.Predef$.$qmark$qmark$qmark(Predef.scala:345)
  at ammonite.$sess.cmd2$Helper.$anonfun$hastype$1(cmd2.sc:13)
  at scala.util.Either.flatMap(Either.scala:352)
  at ammonite.$sess.cmd2$Helper.typecheck$1(cmd2.sc:11)
  at ammonite.$sess.cmd2$Helper.hastype(cmd2.sc:34)
  at ammonite.$sess.cmd2$Helper.inferType(cmd2.sc:47)
  at ammonite.$sess.cmd6$Helper$$anon$1.$anonfun$new$4(cmd6.sc:20)
  at org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85)
  at org.scalatest.OutcomeOf.outcomeOf$(OutcomeOf.scala:83)
  at org.scalatest.OutcomeOf$.outcomeOf(OutcomeOf.scala:104)
  ...
Run completed in 9 milliseconds.
Total number of tests run: 4
Suites: completed 1, aborted 0
Tests: succeeded 1, failed 3, canceled 0, ignored 0, pending 0
*** 3 TESTS FAILED ***
java.lang.AssertionError: assertion failed: an implementation is missing (hastype/If should TypeIf)
  scala.Predef$.assert(Predef.scala:280)
  ammonite.$sess.cmd0$Helper$$anon$1.apply(cmd0.sc:7)
  org.scalatest.WrapperCatchReporter.doApply(CatchReporter.scala:70)
  org.scalatest.CatchReporter.apply(CatchReporter.scala:36)
  org.scalatest.CatchReporter.apply$(CatchReporter.scala:34)
  org.scalatest.WrapperCatchReporter.apply(CatchReporter.scala:63)
  org.scalatest.Suite$.reportTestFailed(Suite.scala:1644)
  org.scalatest.SuperEngine.runTestImpl(Engine.scala:347)
  org.scalatest.flatspec.AnyFlatSpecLike.runTest(AnyFlatSpecLike.scala:1842)
  org.scalatest.flatspec.AnyFlatSpecLike.runTest$(AnyFlatSpecLike.scala:1824)
  org.scalatest.flatspec.AnyFlatSpec.runTest(AnyFlatSpec.scala:1686)
  org.scalatest.flatspec.AnyFlatSpecLike.$anonfun$runTests$1(AnyFlatSpecLike.scala:1900)
  org.scalatest.SuperEngine.$anonfun$runTestsInBranch$1(Engine.scala:413)
  scala.collection.immutable.List.foreach(List.scala:333)
  org.scalatest.SuperEngine.traverseSubNodes$1(Engine.scala:401)
  org.scalatest.SuperEngine.runTestsInBranch(Engine.scala:390)
  org.scalatest.SuperEngine.$anonfun$runTestsInBranch$1(Engine.scala:427)
  scala.collection.immutable.List.foreach(List.scala:333)
  org.scalatest.SuperEngine.traverseSubNodes$1(Engine.scala:401)
  org.scalatest.SuperEngine.runTestsInBranch(Engine.scala:396)
  org.scalatest.SuperEngine.runTestsImpl(Engine.scala:475)
  org.scalatest.flatspec.AnyFlatSpecLike.runTests(AnyFlatSpecLike.scala:1900)
  org.scalatest.flatspec.AnyFlatSpecLike.runTests$(AnyFlatSpecLike.scala:1899)
  org.scalatest.flatspec.AnyFlatSpec.runTests(AnyFlatSpec.scala:1686)
  org.scalatest.Suite.run(Suite.scala:1114)
  org.scalatest.Suite.run$(Suite.scala:1096)
  org.scalatest.flatspec.AnyFlatSpec.org$scalatest$flatspec$AnyFlatSpecLike$$super$run(AnyFlatSpec.scala:1686)
  org.scalatest.flatspec.AnyFlatSpecLike.$anonfun$run$1(AnyFlatSpecLike.scala:1945)
  org.scalatest.SuperEngine.runImpl(Engine.scala:535)
  org.scalatest.flatspec.AnyFlatSpecLike.run(AnyFlatSpecLike.scala:1945)
  org.scalatest.flatspec.AnyFlatSpecLike.run$(AnyFlatSpecLike.scala:1943)
  org.scalatest.flatspec.AnyFlatSpec.run(AnyFlatSpec.scala:1686)
  ammonite.$sess.cmd0$Helper.assertPassed(cmd0.sc:5)
  ammonite.$sess.cmd0$Helper.test(cmd0.sc:18)
  ammonite.$sess.cmd6$Helper.<init>(cmd6.sc:22)
  ammonite.$sess.cmd6$.<clinit>(cmd6.sc:7)
test(new AnyFlatSpec {
  val e1 = Binary(Times, Var("i"), N(3))
  def fun(e: Expr) = Fun("f", ("i", TNumber), TNumber, e)
  "hastype/Fun" should "TypeFun" in {
    assertResult(Right(TFun(("i", TNumber), TNumber))) { inferType(fun(e1)) }
  }

  val badesub = B(true)
  val bade = Binary(Plus, N(1), badesub)
  it should "PropagateFun" in {
    assertResult(Left(StaticTypeError(TBool, badesub, bade))) { inferType(fun(bade)) }
  }
}, 4)
Run starting. Expected test count is: 2
cmd7$Helper$$anon$1:
hastype/Fun
- should TypeFun *** FAILED ***
  scala.NotImplementedError: an implementation is missing
  at scala.Predef$.$qmark$qmark$qmark(Predef.scala:345)
  at ammonite.$sess.cmd2$Helper.hastype(cmd2.sc:38)
  at ammonite.$sess.cmd2$Helper.inferType(cmd2.sc:47)
  at ammonite.$sess.cmd7$Helper$$anon$1.$anonfun$new$1(cmd7.sc:5)
  at org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85)
  at org.scalatest.OutcomeOf.outcomeOf$(OutcomeOf.scala:83)
  at org.scalatest.OutcomeOf$.outcomeOf(OutcomeOf.scala:104)
  at org.scalatest.Transformer.apply(Transformer.scala:22)
  at org.scalatest.Transformer.apply(Transformer.scala:20)
  at org.scalatest.flatspec.AnyFlatSpecLike$$anon$5.apply(AnyFlatSpecLike.scala:1832)
  ...
- should PropagateFun *** FAILED ***
  scala.NotImplementedError: an implementation is missing
  at scala.Predef$.$qmark$qmark$qmark(Predef.scala:345)
  at ammonite.$sess.cmd2$Helper.hastype(cmd2.sc:38)
  at ammonite.$sess.cmd2$Helper.inferType(cmd2.sc:47)
  at ammonite.$sess.cmd7$Helper$$anon$1.$anonfun$new$2(cmd7.sc:11)
  at org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85)
  at org.scalatest.OutcomeOf.outcomeOf$(OutcomeOf.scala:83)
  at org.scalatest.OutcomeOf$.outcomeOf(OutcomeOf.scala:104)
  at org.scalatest.Transformer.apply(Transformer.scala:22)
  at org.scalatest.Transformer.apply(Transformer.scala:20)
  at org.scalatest.flatspec.AnyFlatSpecLike$$anon$5.apply(AnyFlatSpecLike.scala:1832)
  ...
Run completed in 3 milliseconds.
Total number of tests run: 2
Suites: completed 1, aborted 0
Tests: succeeded 0, failed 2, canceled 0, ignored 0, pending 0
*** 2 TESTS FAILED ***
java.lang.AssertionError: assertion failed: an implementation is missing (hastype/Fun should TypeFun)
  scala.Predef$.assert(Predef.scala:280)
  ammonite.$sess.cmd0$Helper$$anon$1.apply(cmd0.sc:7)
  org.scalatest.WrapperCatchReporter.doApply(CatchReporter.scala:70)
  org.scalatest.CatchReporter.apply(CatchReporter.scala:36)
  org.scalatest.CatchReporter.apply$(CatchReporter.scala:34)
  org.scalatest.WrapperCatchReporter.apply(CatchReporter.scala:63)
  org.scalatest.Suite$.reportTestFailed(Suite.scala:1644)
  org.scalatest.SuperEngine.runTestImpl(Engine.scala:347)
  org.scalatest.flatspec.AnyFlatSpecLike.runTest(AnyFlatSpecLike.scala:1842)
  org.scalatest.flatspec.AnyFlatSpecLike.runTest$(AnyFlatSpecLike.scala:1824)
  org.scalatest.flatspec.AnyFlatSpec.runTest(AnyFlatSpec.scala:1686)
  org.scalatest.flatspec.AnyFlatSpecLike.$anonfun$runTests$1(AnyFlatSpecLike.scala:1900)
  org.scalatest.SuperEngine.$anonfun$runTestsInBranch$1(Engine.scala:413)
  scala.collection.immutable.List.foreach(List.scala:333)
  org.scalatest.SuperEngine.traverseSubNodes$1(Engine.scala:401)
  org.scalatest.SuperEngine.runTestsInBranch(Engine.scala:390)
  org.scalatest.SuperEngine.$anonfun$runTestsInBranch$1(Engine.scala:427)
  scala.collection.immutable.List.foreach(List.scala:333)
  org.scalatest.SuperEngine.traverseSubNodes$1(Engine.scala:401)
  org.scalatest.SuperEngine.runTestsInBranch(Engine.scala:396)
  org.scalatest.SuperEngine.runTestsImpl(Engine.scala:475)
  org.scalatest.flatspec.AnyFlatSpecLike.runTests(AnyFlatSpecLike.scala:1900)
  org.scalatest.flatspec.AnyFlatSpecLike.runTests$(AnyFlatSpecLike.scala:1899)
  org.scalatest.flatspec.AnyFlatSpec.runTests(AnyFlatSpec.scala:1686)
  org.scalatest.Suite.run(Suite.scala:1114)
  org.scalatest.Suite.run$(Suite.scala:1096)
  org.scalatest.flatspec.AnyFlatSpec.org$scalatest$flatspec$AnyFlatSpecLike$$super$run(AnyFlatSpec.scala:1686)
  org.scalatest.flatspec.AnyFlatSpecLike.$anonfun$run$1(AnyFlatSpecLike.scala:1945)
  org.scalatest.SuperEngine.runImpl(Engine.scala:535)
  org.scalatest.flatspec.AnyFlatSpecLike.run(AnyFlatSpecLike.scala:1945)
  org.scalatest.flatspec.AnyFlatSpecLike.run$(AnyFlatSpecLike.scala:1943)
  org.scalatest.flatspec.AnyFlatSpec.run(AnyFlatSpec.scala:1686)
  ammonite.$sess.cmd0$Helper.assertPassed(cmd0.sc:5)
  ammonite.$sess.cmd0$Helper.test(cmd0.sc:18)
  ammonite.$sess.cmd7$Helper.<init>(cmd7.sc:13)
  ammonite.$sess.cmd7$.<clinit>(cmd7.sc:7)
test(new AnyFlatSpec {
  val e1 = Binary(Times, Var("i"), Call(Var("f"), N(3)))
  def fun(e: Expr) = Fun("f", ("i", TNumber), TNumber, e)
  val e2 = 
  "hastype/Call" should "TypeCall" in {
    assertResult(Right(TNumber)) { inferType(Call(fun(e1), N(10))) }
  }

  val e3 = Call(B(true), N(1))
  it should "TypeErrorCall" in {
    assertResult(Left(StaticTypeError(TBool, B(true), e3))) { inferType(e3) }
  }

  val badesub = B(true)
  val bade = Binary(Plus, N(1), badesub)
  it should "PropagateCall2" in {
    assertResult(Left(StaticTypeError(TBool, badesub, bade))) { inferType(Call(fun(e1),bade)) }
  }
}, 4)
Run starting. Expected test count is: 3
cmd8$Helper$$anon$1:
hastype/Call
- should TypeCall *** FAILED ***
  scala.NotImplementedError: an implementation is missing
  at scala.Predef$.$qmark$qmark$qmark(Predef.scala:345)
  at ammonite.$sess.cmd2$Helper.hastype(cmd2.sc:41)
  at ammonite.$sess.cmd2$Helper.inferType(cmd2.sc:47)
  at ammonite.$sess.cmd8$Helper$$anon$1.$anonfun$e2$1(cmd8.sc:6)
  at org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85)
  at org.scalatest.OutcomeOf.outcomeOf$(OutcomeOf.scala:83)
  at org.scalatest.OutcomeOf$.outcomeOf(OutcomeOf.scala:104)
  at org.scalatest.Transformer.apply(Transformer.scala:22)
  at org.scalatest.Transformer.apply(Transformer.scala:20)
  at org.scalatest.flatspec.AnyFlatSpecLike$$anon$5.apply(AnyFlatSpecLike.scala:1832)
  ...
- should TypeErrorCall *** FAILED ***
  scala.NotImplementedError: an implementation is missing
  at scala.Predef$.$qmark$qmark$qmark(Predef.scala:345)
  at ammonite.$sess.cmd2$Helper.hastype(cmd2.sc:41)
  at ammonite.$sess.cmd2$Helper.inferType(cmd2.sc:47)
  at ammonite.$sess.cmd8$Helper$$anon$1.$anonfun$new$1(cmd8.sc:11)
  at org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85)
  at org.scalatest.OutcomeOf.outcomeOf$(OutcomeOf.scala:83)
  at org.scalatest.OutcomeOf$.outcomeOf(OutcomeOf.scala:104)
  at org.scalatest.Transformer.apply(Transformer.scala:22)
  at org.scalatest.Transformer.apply(Transformer.scala:20)
  at org.scalatest.flatspec.AnyFlatSpecLike$$anon$5.apply(AnyFlatSpecLike.scala:1832)
  ...
- should PropagateCall2 *** FAILED ***
  scala.NotImplementedError: an implementation is missing
  at scala.Predef$.$qmark$qmark$qmark(Predef.scala:345)
  at ammonite.$sess.cmd2$Helper.hastype(cmd2.sc:41)
  at ammonite.$sess.cmd2$Helper.inferType(cmd2.sc:47)
  at ammonite.$sess.cmd8$Helper$$anon$1.$anonfun$new$2(cmd8.sc:17)
  at org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85)
  at org.scalatest.OutcomeOf.outcomeOf$(OutcomeOf.scala:83)
  at org.scalatest.OutcomeOf$.outcomeOf(OutcomeOf.scala:104)
  at org.scalatest.Transformer.apply(Transformer.scala:22)
  at org.scalatest.Transformer.apply(Transformer.scala:20)
  at org.scalatest.flatspec.AnyFlatSpecLike$$anon$5.apply(AnyFlatSpecLike.scala:1832)
  ...
Run completed in 3 milliseconds.
Total number of tests run: 3
Suites: completed 1, aborted 0
Tests: succeeded 0, failed 3, canceled 0, ignored 0, pending 0
*** 3 TESTS FAILED ***
java.lang.AssertionError: assertion failed: an implementation is missing (hastype/Call should TypeCall)
  scala.Predef$.assert(Predef.scala:280)
  ammonite.$sess.cmd0$Helper$$anon$1.apply(cmd0.sc:7)
  org.scalatest.WrapperCatchReporter.doApply(CatchReporter.scala:70)
  org.scalatest.CatchReporter.apply(CatchReporter.scala:36)
  org.scalatest.CatchReporter.apply$(CatchReporter.scala:34)
  org.scalatest.WrapperCatchReporter.apply(CatchReporter.scala:63)
  org.scalatest.Suite$.reportTestFailed(Suite.scala:1644)
  org.scalatest.SuperEngine.runTestImpl(Engine.scala:347)
  org.scalatest.flatspec.AnyFlatSpecLike.runTest(AnyFlatSpecLike.scala:1842)
  org.scalatest.flatspec.AnyFlatSpecLike.runTest$(AnyFlatSpecLike.scala:1824)
  org.scalatest.flatspec.AnyFlatSpec.runTest(AnyFlatSpec.scala:1686)
  org.scalatest.flatspec.AnyFlatSpecLike.$anonfun$runTests$1(AnyFlatSpecLike.scala:1900)
  org.scalatest.SuperEngine.$anonfun$runTestsInBranch$1(Engine.scala:413)
  scala.collection.immutable.List.foreach(List.scala:333)
  org.scalatest.SuperEngine.traverseSubNodes$1(Engine.scala:401)
  org.scalatest.SuperEngine.runTestsInBranch(Engine.scala:390)
  org.scalatest.SuperEngine.$anonfun$runTestsInBranch$1(Engine.scala:427)
  scala.collection.immutable.List.foreach(List.scala:333)
  org.scalatest.SuperEngine.traverseSubNodes$1(Engine.scala:401)
  org.scalatest.SuperEngine.runTestsInBranch(Engine.scala:396)
  org.scalatest.SuperEngine.runTestsImpl(Engine.scala:475)
  org.scalatest.flatspec.AnyFlatSpecLike.runTests(AnyFlatSpecLike.scala:1900)
  org.scalatest.flatspec.AnyFlatSpecLike.runTests$(AnyFlatSpecLike.scala:1899)
  org.scalatest.flatspec.AnyFlatSpec.runTests(AnyFlatSpec.scala:1686)
  org.scalatest.Suite.run(Suite.scala:1114)
  org.scalatest.Suite.run$(Suite.scala:1096)
  org.scalatest.flatspec.AnyFlatSpec.org$scalatest$flatspec$AnyFlatSpecLike$$super$run(AnyFlatSpec.scala:1686)
  org.scalatest.flatspec.AnyFlatSpecLike.$anonfun$run$1(AnyFlatSpecLike.scala:1945)
  org.scalatest.SuperEngine.runImpl(Engine.scala:535)
  org.scalatest.flatspec.AnyFlatSpecLike.run(AnyFlatSpecLike.scala:1945)
  org.scalatest.flatspec.AnyFlatSpecLike.run$(AnyFlatSpecLike.scala:1943)
  org.scalatest.flatspec.AnyFlatSpec.run(AnyFlatSpec.scala:1686)
  ammonite.$sess.cmd0$Helper.assertPassed(cmd0.sc:5)
  ammonite.$sess.cmd0$Helper.test(cmd0.sc:18)
  ammonite.$sess.cmd8$Helper.<init>(cmd8.sc:19)
  ammonite.$sess.cmd8$.<clinit>(cmd8.sc:7)
test(new AnyFlatSpec {
  val factorial = Fun("fact", ("n", TNumber), TNumber,
    If(Binary(Eq, Var("n"), N(1)),
    N(1),
    Binary(Times, Var("n"), Call(Var("fact"), Binary(Plus, Var("n"), N(-1)))))
  )
  "hastype" should "type check factorial" in {
    assertResult(Right(TNumber)) { inferType(Call(factorial, N(4))) }
  }
}, 2)
Run starting. Expected test count is: 1
cmd9$Helper$$anon$1:
hastype
- should type check factorial *** FAILED ***
  scala.NotImplementedError: an implementation is missing
  at scala.Predef$.$qmark$qmark$qmark(Predef.scala:345)
  at ammonite.$sess.cmd2$Helper.hastype(cmd2.sc:41)
  at ammonite.$sess.cmd2$Helper.inferType(cmd2.sc:47)
  at ammonite.$sess.cmd9$Helper$$anon$1.$anonfun$new$1(cmd9.sc:8)
  at org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85)
  at org.scalatest.OutcomeOf.outcomeOf$(OutcomeOf.scala:83)
  at org.scalatest.OutcomeOf$.outcomeOf(OutcomeOf.scala:104)
  at org.scalatest.Transformer.apply(Transformer.scala:22)
  at org.scalatest.Transformer.apply(Transformer.scala:20)
  at org.scalatest.flatspec.AnyFlatSpecLike$$anon$5.apply(AnyFlatSpecLike.scala:1832)
  ...
Run completed in 1 millisecond.
Total number of tests run: 1
Suites: completed 1, aborted 0
Tests: succeeded 0, failed 1, canceled 0, ignored 0, pending 0
*** 1 TEST FAILED ***
java.lang.AssertionError: assertion failed: an implementation is missing (hastype should type check factorial)
  scala.Predef$.assert(Predef.scala:280)
  ammonite.$sess.cmd0$Helper$$anon$1.apply(cmd0.sc:7)
  org.scalatest.WrapperCatchReporter.doApply(CatchReporter.scala:70)
  org.scalatest.CatchReporter.apply(CatchReporter.scala:36)
  org.scalatest.CatchReporter.apply$(CatchReporter.scala:34)
  org.scalatest.WrapperCatchReporter.apply(CatchReporter.scala:63)
  org.scalatest.Suite$.reportTestFailed(Suite.scala:1644)
  org.scalatest.SuperEngine.runTestImpl(Engine.scala:347)
  org.scalatest.flatspec.AnyFlatSpecLike.runTest(AnyFlatSpecLike.scala:1842)
  org.scalatest.flatspec.AnyFlatSpecLike.runTest$(AnyFlatSpecLike.scala:1824)
  org.scalatest.flatspec.AnyFlatSpec.runTest(AnyFlatSpec.scala:1686)
  org.scalatest.flatspec.AnyFlatSpecLike.$anonfun$runTests$1(AnyFlatSpecLike.scala:1900)
  org.scalatest.SuperEngine.$anonfun$runTestsInBranch$1(Engine.scala:413)
  scala.collection.immutable.List.foreach(List.scala:333)
  org.scalatest.SuperEngine.traverseSubNodes$1(Engine.scala:401)
  org.scalatest.SuperEngine.runTestsInBranch(Engine.scala:390)
  org.scalatest.SuperEngine.$anonfun$runTestsInBranch$1(Engine.scala:427)
  scala.collection.immutable.List.foreach(List.scala:333)
  org.scalatest.SuperEngine.traverseSubNodes$1(Engine.scala:401)
  org.scalatest.SuperEngine.runTestsInBranch(Engine.scala:396)
  org.scalatest.SuperEngine.runTestsImpl(Engine.scala:475)
  org.scalatest.flatspec.AnyFlatSpecLike.runTests(AnyFlatSpecLike.scala:1900)
  org.scalatest.flatspec.AnyFlatSpecLike.runTests$(AnyFlatSpecLike.scala:1899)
  org.scalatest.flatspec.AnyFlatSpec.runTests(AnyFlatSpec.scala:1686)
  org.scalatest.Suite.run(Suite.scala:1114)
  org.scalatest.Suite.run$(Suite.scala:1096)
  org.scalatest.flatspec.AnyFlatSpec.org$scalatest$flatspec$AnyFlatSpecLike$$super$run(AnyFlatSpec.scala:1686)
  org.scalatest.flatspec.AnyFlatSpecLike.$anonfun$run$1(AnyFlatSpecLike.scala:1945)
  org.scalatest.SuperEngine.runImpl(Engine.scala:535)
  org.scalatest.flatspec.AnyFlatSpecLike.run(AnyFlatSpecLike.scala:1945)
  org.scalatest.flatspec.AnyFlatSpecLike.run$(AnyFlatSpecLike.scala:1943)
  org.scalatest.flatspec.AnyFlatSpec.run(AnyFlatSpec.scala:1686)
  ammonite.$sess.cmd0$Helper.assertPassed(cmd0.sc:5)
  ammonite.$sess.cmd0$Helper.test(cmd0.sc:18)
  ammonite.$sess.cmd9$Helper.<init>(cmd9.sc:10)
  ammonite.$sess.cmd9$.<clinit>(cmd9.sc:7)

31.3 Mutation Effects

31.3.1 Defining Generic DoWith Methods

Recall the idea of encapulating a state transforming function S => (S, A) as a collection-like data type (Section 30.5), which we call a DoWith[S, A]:

sealed class DoWith[S, A] private (doer: S => (S, A)) {
  def map[B](f: A => B): DoWith[S, B] = new DoWith[S, B]({
    (s: S) => {
      val (s_, a) = doer(s)
      (s_, f(a))
    }
  })

  def flatMap[B](f: A => DoWith[S, B]): DoWith[S, B] = new DoWith[S, B]({
    (s: S) => {
      val (s_, a) = doer(s)
      f(a)(s_)
    }
  })

  def apply(s: S): (S, A) = doer(s)
}

object DoWith {
  def doget[S]: DoWith[S, S] = new DoWith[S, S]({ s => (s, s) })
  def doput[S](s: S): DoWith[S, Unit] = new DoWith[S, Unit]({ _ => (s, ()) })
}

import DoWith._
defined class DoWith
defined object DoWith
import DoWith._

Consider a DoWith[S,A] as a โ€œcollectionโ€ holding an A somewhat like List[A] or Option[A]. While List[A] encapsulates a sequence of elements of type A elements and Option[A] encapsulates an optional A, a DoWith[S, A] encapsulates a computation that results in an A, using an input-output state S (i.e., a S => (S, A) function). It is collection-like because it also has map and flatMap methods to transform that computation.

We also define two functions for a client to create a DoWith[S, A] encapsulating particular S => (S, A){.scala functions}:

  • The doget[S] method constructs a DoWith[S, S] that makes the โ€œcurrentโ€ state the result (i.e., s => (s, s)). Intuitively, it โ€œgetsโ€ the state.
  • The doput[S](s: S) method constructs a DoWith[S, Unit] that makes the given state s the โ€œcurrentโ€ state (i.e., _ => (s, ())). Intuitively, it โ€œputsโ€ s into the state.

We require the client to create DoWith[S, A] values using only the doget and doput constructors.

Exercise 31.4 (4 points) Read the implementations map[B] and flatMap[B] methods of DoWith[S, A] above. Explain how they transform the encapsulated doer: S => (S, A) function. Compare and contrast themโ€”what do they do that is same, and what is the key difference between them?

Edit this cell:

???

As a DoWith[S, A] encapsulates any function of type S => (S, A), there are other commonly needed functions of this type. We implement methods for constructing DoWith[S, A] encapsulating two more commonly-needed computations in terms of doget and doput.

  • The doreturn[S, A](a: A) method constructs a DoWith[S, A] that leaves the โ€œcurrentโ€ state as-is and returns the given result a (i.e., s => (s, a)). It technically does not need to be given in the library, as it can be defined in terms of doget and map.
  • The domodify[S](f: S => S) method constructs a DoWith[S, Unit] that โ€œmodifiesโ€ the state using the given function f: S => S (i.e., s => (f(s), ())). It technically does not need to be given in the library, as it can be defined in terms of doget, doput, and flatMap.

Exercise 31.5 (4 points) Implement doreturn[S, A](a: A) that creates a DoWith[S, A] that encapsulates the computation (s: S) => (s, a) using doget, doput, map, and/or flatMap.

Edit this cell:

def doreturn[S, A](a: A): DoWith[S, A] =
  ???
defined function doreturn

Tests

test(new AnyFlatSpec {
  "doreturn" should "Test1" in { assertResult( (0,1) ) { doreturn(1)(0) }}
  it should "Test2" in { assertResult( (2,"test") ) { doreturn("test")(2) }}
  it should "Test3" in { assertResult( (2,List(1,2,3)) ) { doreturn(List(1,2,3))(2) }}
}, 4)
Run starting. Expected test count is: 3
cmd12$Helper$$anon$1:
doreturn
- should Test1 *** FAILED ***
  scala.NotImplementedError: an implementation is missing
  at scala.Predef$.$qmark$qmark$qmark(Predef.scala:345)
  at ammonite.$sess.cmd11$Helper.doreturn(cmd11.sc:2)
  at ammonite.$sess.cmd12$Helper$$anon$1.$anonfun$new$1(cmd12.sc:2)
  at org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85)
  at org.scalatest.OutcomeOf.outcomeOf$(OutcomeOf.scala:83)
  at org.scalatest.OutcomeOf$.outcomeOf(OutcomeOf.scala:104)
  at org.scalatest.Transformer.apply(Transformer.scala:22)
  at org.scalatest.Transformer.apply(Transformer.scala:20)
  at org.scalatest.flatspec.AnyFlatSpecLike$$anon$5.apply(AnyFlatSpecLike.scala:1832)
  at org.scalatest.TestSuite.withFixture(TestSuite.scala:196)
  ...
- should Test2 *** FAILED ***
  scala.NotImplementedError: an implementation is missing
  at scala.Predef$.$qmark$qmark$qmark(Predef.scala:345)
  at ammonite.$sess.cmd11$Helper.doreturn(cmd11.sc:2)
  at ammonite.$sess.cmd12$Helper$$anon$1.$anonfun$new$2(cmd12.sc:3)
  at org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85)
  at org.scalatest.OutcomeOf.outcomeOf$(OutcomeOf.scala:83)
  at org.scalatest.OutcomeOf$.outcomeOf(OutcomeOf.scala:104)
  at org.scalatest.Transformer.apply(Transformer.scala:22)
  at org.scalatest.Transformer.apply(Transformer.scala:20)
  at org.scalatest.flatspec.AnyFlatSpecLike$$anon$5.apply(AnyFlatSpecLike.scala:1832)
  at org.scalatest.TestSuite.withFixture(TestSuite.scala:196)
  ...
- should Test3 *** FAILED ***
  scala.NotImplementedError: an implementation is missing
  at scala.Predef$.$qmark$qmark$qmark(Predef.scala:345)
  at ammonite.$sess.cmd11$Helper.doreturn(cmd11.sc:2)
  at ammonite.$sess.cmd12$Helper$$anon$1.$anonfun$new$3(cmd12.sc:4)
  at org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85)
  at org.scalatest.OutcomeOf.outcomeOf$(OutcomeOf.scala:83)
  at org.scalatest.OutcomeOf$.outcomeOf(OutcomeOf.scala:104)
  at org.scalatest.Transformer.apply(Transformer.scala:22)
  at org.scalatest.Transformer.apply(Transformer.scala:20)
  at org.scalatest.flatspec.AnyFlatSpecLike$$anon$5.apply(AnyFlatSpecLike.scala:1832)
  at org.scalatest.TestSuite.withFixture(TestSuite.scala:196)
  ...
Run completed in 3 milliseconds.
Total number of tests run: 3
Suites: completed 1, aborted 0
Tests: succeeded 0, failed 3, canceled 0, ignored 0, pending 0
*** 3 TESTS FAILED ***
java.lang.AssertionError: assertion failed: an implementation is missing (doreturn should Test1)
  scala.Predef$.assert(Predef.scala:280)
  ammonite.$sess.cmd0$Helper$$anon$1.apply(cmd0.sc:7)
  org.scalatest.WrapperCatchReporter.doApply(CatchReporter.scala:70)
  org.scalatest.CatchReporter.apply(CatchReporter.scala:36)
  org.scalatest.CatchReporter.apply$(CatchReporter.scala:34)
  org.scalatest.WrapperCatchReporter.apply(CatchReporter.scala:63)
  org.scalatest.Suite$.reportTestFailed(Suite.scala:1644)
  org.scalatest.SuperEngine.runTestImpl(Engine.scala:347)
  org.scalatest.flatspec.AnyFlatSpecLike.runTest(AnyFlatSpecLike.scala:1842)
  org.scalatest.flatspec.AnyFlatSpecLike.runTest$(AnyFlatSpecLike.scala:1824)
  org.scalatest.flatspec.AnyFlatSpec.runTest(AnyFlatSpec.scala:1686)
  org.scalatest.flatspec.AnyFlatSpecLike.$anonfun$runTests$1(AnyFlatSpecLike.scala:1900)
  org.scalatest.SuperEngine.$anonfun$runTestsInBranch$1(Engine.scala:413)
  scala.collection.immutable.List.foreach(List.scala:333)
  org.scalatest.SuperEngine.traverseSubNodes$1(Engine.scala:401)
  org.scalatest.SuperEngine.runTestsInBranch(Engine.scala:390)
  org.scalatest.SuperEngine.$anonfun$runTestsInBranch$1(Engine.scala:427)
  scala.collection.immutable.List.foreach(List.scala:333)
  org.scalatest.SuperEngine.traverseSubNodes$1(Engine.scala:401)
  org.scalatest.SuperEngine.runTestsInBranch(Engine.scala:396)
  org.scalatest.SuperEngine.runTestsImpl(Engine.scala:475)
  org.scalatest.flatspec.AnyFlatSpecLike.runTests(AnyFlatSpecLike.scala:1900)
  org.scalatest.flatspec.AnyFlatSpecLike.runTests$(AnyFlatSpecLike.scala:1899)
  org.scalatest.flatspec.AnyFlatSpec.runTests(AnyFlatSpec.scala:1686)
  org.scalatest.Suite.run(Suite.scala:1114)
  org.scalatest.Suite.run$(Suite.scala:1096)
  org.scalatest.flatspec.AnyFlatSpec.org$scalatest$flatspec$AnyFlatSpecLike$$super$run(AnyFlatSpec.scala:1686)
  org.scalatest.flatspec.AnyFlatSpecLike.$anonfun$run$1(AnyFlatSpecLike.scala:1945)
  org.scalatest.SuperEngine.runImpl(Engine.scala:535)
  org.scalatest.flatspec.AnyFlatSpecLike.run(AnyFlatSpecLike.scala:1945)
  org.scalatest.flatspec.AnyFlatSpecLike.run$(AnyFlatSpecLike.scala:1943)
  org.scalatest.flatspec.AnyFlatSpec.run(AnyFlatSpec.scala:1686)
  ammonite.$sess.cmd0$Helper.assertPassed(cmd0.sc:5)
  ammonite.$sess.cmd0$Helper.test(cmd0.sc:18)
  ammonite.$sess.cmd12$Helper.<init>(cmd12.sc:5)
  ammonite.$sess.cmd12$.<clinit>(cmd12.sc:7)

Exercise 31.6 (4 points) Implement domodify[S](f: S => S) that creates a DoWith[S, Unit] that encapsulates the computation (s: S) => (f(s), ()) using doget, doput, map, and/or flatMap.

Edit this cell:

def domodify[S](f: S => S): DoWith[S, Unit] = 
  ???
defined function domodify

Notes

  • Hint: To define doreturn and domodify, it might help first to do type-directed programming where you ignore what a DoWith[S, A] actually is and think of it as Either[S, A] or abstractly as M[S, A] for an unknown type constructor M. There only limited things you can do by composing doget, doput, map, and flatMap.

Tests

test(new AnyFlatSpec {
  "domodify" should "Test1" in { assertResult( (6,()) ) { domodify({a:Int => 2*a})(3) }}
  it should "Test2" in { assertResult( ("testtest",()) ) { domodify({x:String => x+x})("test") }}
  it should "Test3" in { assertResult( (List(1,2,3,4),()) ) { domodify({l:List[Int] => l:+4})(List(1,2,3))}}
}, 4)
Run starting. Expected test count is: 3
cmd14$Helper$$anon$1:
domodify
- should Test1 *** FAILED ***
  scala.NotImplementedError: an implementation is missing
  at scala.Predef$.$qmark$qmark$qmark(Predef.scala:345)
  at ammonite.$sess.cmd13$Helper.domodify(cmd13.sc:2)
  at ammonite.$sess.cmd14$Helper$$anon$1.$anonfun$new$1(cmd14.sc:2)
  at org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85)
  at org.scalatest.OutcomeOf.outcomeOf$(OutcomeOf.scala:83)
  at org.scalatest.OutcomeOf$.outcomeOf(OutcomeOf.scala:104)
  at org.scalatest.Transformer.apply(Transformer.scala:22)
  at org.scalatest.Transformer.apply(Transformer.scala:20)
  at org.scalatest.flatspec.AnyFlatSpecLike$$anon$5.apply(AnyFlatSpecLike.scala:1832)
  at org.scalatest.TestSuite.withFixture(TestSuite.scala:196)
  ...
- should Test2 *** FAILED ***
  scala.NotImplementedError: an implementation is missing
  at scala.Predef$.$qmark$qmark$qmark(Predef.scala:345)
  at ammonite.$sess.cmd13$Helper.domodify(cmd13.sc:2)
  at ammonite.$sess.cmd14$Helper$$anon$1.$anonfun$new$3(cmd14.sc:3)
  at org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85)
  at org.scalatest.OutcomeOf.outcomeOf$(OutcomeOf.scala:83)
  at org.scalatest.OutcomeOf$.outcomeOf(OutcomeOf.scala:104)
  at org.scalatest.Transformer.apply(Transformer.scala:22)
  at org.scalatest.Transformer.apply(Transformer.scala:20)
  at org.scalatest.flatspec.AnyFlatSpecLike$$anon$5.apply(AnyFlatSpecLike.scala:1832)
  at org.scalatest.TestSuite.withFixture(TestSuite.scala:196)
  ...
- should Test3 *** FAILED ***
  scala.NotImplementedError: an implementation is missing
  at scala.Predef$.$qmark$qmark$qmark(Predef.scala:345)
  at ammonite.$sess.cmd13$Helper.domodify(cmd13.sc:2)
  at ammonite.$sess.cmd14$Helper$$anon$1.$anonfun$new$5(cmd14.sc:4)
  at org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85)
  at org.scalatest.OutcomeOf.outcomeOf$(OutcomeOf.scala:83)
  at org.scalatest.OutcomeOf$.outcomeOf(OutcomeOf.scala:104)
  at org.scalatest.Transformer.apply(Transformer.scala:22)
  at org.scalatest.Transformer.apply(Transformer.scala:20)
  at org.scalatest.flatspec.AnyFlatSpecLike$$anon$5.apply(AnyFlatSpecLike.scala:1832)
  at org.scalatest.TestSuite.withFixture(TestSuite.scala:196)
  ...
Run completed in 4 milliseconds.
Total number of tests run: 3
Suites: completed 1, aborted 0
Tests: succeeded 0, failed 3, canceled 0, ignored 0, pending 0
*** 3 TESTS FAILED ***
java.lang.AssertionError: assertion failed: an implementation is missing (domodify should Test1)
  scala.Predef$.assert(Predef.scala:280)
  ammonite.$sess.cmd0$Helper$$anon$1.apply(cmd0.sc:7)
  org.scalatest.WrapperCatchReporter.doApply(CatchReporter.scala:70)
  org.scalatest.CatchReporter.apply(CatchReporter.scala:36)
  org.scalatest.CatchReporter.apply$(CatchReporter.scala:34)
  org.scalatest.WrapperCatchReporter.apply(CatchReporter.scala:63)
  org.scalatest.Suite$.reportTestFailed(Suite.scala:1644)
  org.scalatest.SuperEngine.runTestImpl(Engine.scala:347)
  org.scalatest.flatspec.AnyFlatSpecLike.runTest(AnyFlatSpecLike.scala:1842)
  org.scalatest.flatspec.AnyFlatSpecLike.runTest$(AnyFlatSpecLike.scala:1824)
  org.scalatest.flatspec.AnyFlatSpec.runTest(AnyFlatSpec.scala:1686)
  org.scalatest.flatspec.AnyFlatSpecLike.$anonfun$runTests$1(AnyFlatSpecLike.scala:1900)
  org.scalatest.SuperEngine.$anonfun$runTestsInBranch$1(Engine.scala:413)
  scala.collection.immutable.List.foreach(List.scala:333)
  org.scalatest.SuperEngine.traverseSubNodes$1(Engine.scala:401)
  org.scalatest.SuperEngine.runTestsInBranch(Engine.scala:390)
  org.scalatest.SuperEngine.$anonfun$runTestsInBranch$1(Engine.scala:427)
  scala.collection.immutable.List.foreach(List.scala:333)
  org.scalatest.SuperEngine.traverseSubNodes$1(Engine.scala:401)
  org.scalatest.SuperEngine.runTestsInBranch(Engine.scala:396)
  org.scalatest.SuperEngine.runTestsImpl(Engine.scala:475)
  org.scalatest.flatspec.AnyFlatSpecLike.runTests(AnyFlatSpecLike.scala:1900)
  org.scalatest.flatspec.AnyFlatSpecLike.runTests$(AnyFlatSpecLike.scala:1899)
  org.scalatest.flatspec.AnyFlatSpec.runTests(AnyFlatSpec.scala:1686)
  org.scalatest.Suite.run(Suite.scala:1114)
  org.scalatest.Suite.run$(Suite.scala:1096)
  org.scalatest.flatspec.AnyFlatSpec.org$scalatest$flatspec$AnyFlatSpecLike$$super$run(AnyFlatSpec.scala:1686)
  org.scalatest.flatspec.AnyFlatSpecLike.$anonfun$run$1(AnyFlatSpecLike.scala:1945)
  org.scalatest.SuperEngine.runImpl(Engine.scala:535)
  org.scalatest.flatspec.AnyFlatSpecLike.run(AnyFlatSpecLike.scala:1945)
  org.scalatest.flatspec.AnyFlatSpecLike.run$(AnyFlatSpecLike.scala:1943)
  org.scalatest.flatspec.AnyFlatSpec.run(AnyFlatSpec.scala:1686)
  ammonite.$sess.cmd0$Helper.assertPassed(cmd0.sc:5)
  ammonite.$sess.cmd0$Helper.test(cmd0.sc:18)
  ammonite.$sess.cmd14$Helper.<init>(cmd14.sc:5)
  ammonite.$sess.cmd14$.<clinit>(cmd14.sc:7)

31.3.2 Renaming Bound Variables

Recall that with static scoping, we see expressions as being equivalent up to the renaming of bound variables (Section 14.4). For example, we see the following two expressions as being equivalent for the purposes of the language implementation:

const four = (2 + 2); (four + four)
const x = (2 + 2); (x + x)

even though the concrete syntax for the human user is different in their choice of variable names.

While being able to choose variable names that shadows another variable is important for the human user, we have seen that clashing variable names adds complexity to the language implementation. For example, mishandling of clashing variable names results in accidental dynamic scoping (Section 19.2) and substitution has to account for variable shadowing (Section 21.9).

Observing that renaming bound variables preserves meaning for the language implementation, one approach for simplifying the handling of variable scope is to implement a lowering pass that renames bound variables in a consistent manner so that variable names are globally unique. For example, we could lower the following expression

const a = ((a) => a)(1) + ((a) => a)(2); a

by renaming bound variables to, for example,

const a_0 = ((a_1) => a_1)(1) + ((a_2) => a_2)(2); a_0

We will implement the above lowering pass in a few steps.

Exercise 31.7 (4 points) Write a function freshVar(x: String) that returns a function of type Int => (Int, String), which takes a current index-state i: Int and returns the pair of the next index state i + 1 and the string x with the index appended and separated by "_" (specifically, s"${x}_${i}"):

Edit this cell:

def freshVar(x: String): Int => (Int, String) =
  { i =>
      ???
  }
defined function freshVar

Tests

test(new AnyFlatSpec with Matchers with ScalaCheckPropertyChecks {
  "freshVar" should "satisfy the property" in {
    forAll ("x", "i") { (x: String, i: Int) =>
      freshVar(x)(i) should be (i + 1, s"${x}_${i}")
    }
  }
}, 4)
Run starting. Expected test count is: 1
cmd16$Helper$$anon$1:
freshVar
- should satisfy the property *** FAILED ***
  NotImplementedError was thrown during property evaluation.
    Message: an implementation is missing
    Occurred when passed generated values (
      x = "",
      i = 0 // 31 shrinks (orig: 2147483647)
    )
  Init Seed: -1879288200601226907
Run completed in 113 milliseconds.
Total number of tests run: 1
Suites: completed 1, aborted 0
Tests: succeeded 0, failed 1, canceled 0, ignored 0, pending 0
*** 1 TEST FAILED ***
java.lang.AssertionError: assertion failed: NotImplementedError was thrown during property evaluation.
  Message: an implementation is missing
  Occurred when passed generated values (
    x = "",
    i = 0 // 29 shrinks (orig: -355998482)
  )
Init Seed: -7734540921015625918 (freshVar should satisfy the property)
  scala.Predef$.assert(Predef.scala:280)
  ammonite.$sess.cmd0$Helper$$anon$1.apply(cmd0.sc:7)
  org.scalatest.WrapperCatchReporter.doApply(CatchReporter.scala:70)
  org.scalatest.CatchReporter.apply(CatchReporter.scala:36)
  org.scalatest.CatchReporter.apply$(CatchReporter.scala:34)
  org.scalatest.WrapperCatchReporter.apply(CatchReporter.scala:63)
  org.scalatest.Suite$.reportTestFailed(Suite.scala:1644)
  org.scalatest.SuperEngine.runTestImpl(Engine.scala:347)
  org.scalatest.flatspec.AnyFlatSpecLike.runTest(AnyFlatSpecLike.scala:1842)
  org.scalatest.flatspec.AnyFlatSpecLike.runTest$(AnyFlatSpecLike.scala:1824)
  org.scalatest.flatspec.AnyFlatSpec.runTest(AnyFlatSpec.scala:1686)
  org.scalatest.flatspec.AnyFlatSpecLike.$anonfun$runTests$1(AnyFlatSpecLike.scala:1900)
  org.scalatest.SuperEngine.$anonfun$runTestsInBranch$1(Engine.scala:413)
  scala.collection.immutable.List.foreach(List.scala:333)
  org.scalatest.SuperEngine.traverseSubNodes$1(Engine.scala:401)
  org.scalatest.SuperEngine.runTestsInBranch(Engine.scala:390)
  org.scalatest.SuperEngine.$anonfun$runTestsInBranch$1(Engine.scala:427)
  scala.collection.immutable.List.foreach(List.scala:333)
  org.scalatest.SuperEngine.traverseSubNodes$1(Engine.scala:401)
  org.scalatest.SuperEngine.runTestsInBranch(Engine.scala:396)
  org.scalatest.SuperEngine.runTestsImpl(Engine.scala:475)
  org.scalatest.flatspec.AnyFlatSpecLike.runTests(AnyFlatSpecLike.scala:1900)
  org.scalatest.flatspec.AnyFlatSpecLike.runTests$(AnyFlatSpecLike.scala:1899)
  org.scalatest.flatspec.AnyFlatSpec.runTests(AnyFlatSpec.scala:1686)
  org.scalatest.Suite.run(Suite.scala:1114)
  org.scalatest.Suite.run$(Suite.scala:1096)
  org.scalatest.flatspec.AnyFlatSpec.org$scalatest$flatspec$AnyFlatSpecLike$$super$run(AnyFlatSpec.scala:1686)
  org.scalatest.flatspec.AnyFlatSpecLike.$anonfun$run$1(AnyFlatSpecLike.scala:1945)
  org.scalatest.SuperEngine.runImpl(Engine.scala:535)
  org.scalatest.flatspec.AnyFlatSpecLike.run(AnyFlatSpecLike.scala:1945)
  org.scalatest.flatspec.AnyFlatSpecLike.run$(AnyFlatSpecLike.scala:1943)
  org.scalatest.flatspec.AnyFlatSpec.run(AnyFlatSpec.scala:1686)
  ammonite.$sess.cmd0$Helper.assertPassed(cmd0.sc:5)
  ammonite.$sess.cmd0$Helper.test(cmd0.sc:18)
  ammonite.$sess.cmd16$Helper.<init>(cmd16.sc:7)
  ammonite.$sess.cmd16$.<clinit>(cmd16.sc:7)

Aside: Writing lots of tests is painful. In the above, we use an idea called property-based testing to make it less painful and more effective. A property-based testing library enables specifying a property on inputs like in the above for x: String and i: Int, and the library will choose lots of random inputs with which to check the property. Importantly, the library also enables the client to specify how to generate inputs (e.g., what range, what distribution), though we do not do anything special to control the input generation in the above.

Exercise 31.8 (4 points) Write a function freshVarWith(x: String): DoWith[Int, String] that behaves like freshVar(x: String): Int => (Int, String) in Exercise 31.7.

Edit this cell:

def freshVarWith(x: String): DoWith[Int, String] =
  ???
defined function freshVarWith

Notes

  • Hint: Remember that DoWith[Int, String] encapsulates a function of type Int => (Int, String). Use freshVar as a guide to creating the DoWith[Int, String] using doget, doput, map, and/or flatMap.
  • For accelerated students, you may try to use a for-yield expression to replace your map and flatMap calls.

A lowering pass is a transformation function from Expr => Expr. To rename bound variables in a consistent manner, we need an enviroment to remember what the name should be for a free variable use in the input Expr. Thus, we need to define a helper function rename(env: Map[String, String], e: Expr) that takes as input an env: Map[String, String] that maps original names to new names for the free variable uses in e.

We also need a way to choose how to rename bound variables so that they are unique. The client of rename might want to rename variables uniquely in different ways (e.g., using an integer counter, using the original name with an integer counter). Thus, we add an additional callback parameter

fresh: String => DoWith[S, String]

for the client to specify how they want to specify the fresh name given the original name where they can choose a state type S to use through renaming.

Tests

test(new AnyFlatSpec with Matchers with ScalaCheckPropertyChecks {
  "freshVarWith" should "satisfy the property" in {
    forAll ("x", "i") { (x: String, i: Int) =>
      freshVarWith(x)(i) should be (i + 1, s"${x}_${i}")
    }
  }
}, 4)
Run starting. Expected test count is: 1
cmd18$Helper$$anon$1:
freshVarWith
- should satisfy the property *** FAILED ***
  NotImplementedError was thrown during property evaluation.
    Message: an implementation is missing
    Occurred when passed generated values (
      x = "",
      i = 0 // 1 shrink (orig: -1)
    )
  Init Seed: -837283807232477770
Run completed in 3 milliseconds.
Total number of tests run: 1
Suites: completed 1, aborted 0
Tests: succeeded 0, failed 1, canceled 0, ignored 0, pending 0
*** 1 TEST FAILED ***
java.lang.AssertionError: assertion failed: NotImplementedError was thrown during property evaluation.
  Message: an implementation is missing
  Occurred when passed generated values (
    x = "",
    i = 0 // 27 shrinks (orig: -92138436)
  )
Init Seed: 3977546869453640399 (freshVarWith should satisfy the property)
  scala.Predef$.assert(Predef.scala:280)
  ammonite.$sess.cmd0$Helper$$anon$1.apply(cmd0.sc:7)
  org.scalatest.WrapperCatchReporter.doApply(CatchReporter.scala:70)
  org.scalatest.CatchReporter.apply(CatchReporter.scala:36)
  org.scalatest.CatchReporter.apply$(CatchReporter.scala:34)
  org.scalatest.WrapperCatchReporter.apply(CatchReporter.scala:63)
  org.scalatest.Suite$.reportTestFailed(Suite.scala:1644)
  org.scalatest.SuperEngine.runTestImpl(Engine.scala:347)
  org.scalatest.flatspec.AnyFlatSpecLike.runTest(AnyFlatSpecLike.scala:1842)
  org.scalatest.flatspec.AnyFlatSpecLike.runTest$(AnyFlatSpecLike.scala:1824)
  org.scalatest.flatspec.AnyFlatSpec.runTest(AnyFlatSpec.scala:1686)
  org.scalatest.flatspec.AnyFlatSpecLike.$anonfun$runTests$1(AnyFlatSpecLike.scala:1900)
  org.scalatest.SuperEngine.$anonfun$runTestsInBranch$1(Engine.scala:413)
  scala.collection.immutable.List.foreach(List.scala:333)
  org.scalatest.SuperEngine.traverseSubNodes$1(Engine.scala:401)
  org.scalatest.SuperEngine.runTestsInBranch(Engine.scala:390)
  org.scalatest.SuperEngine.$anonfun$runTestsInBranch$1(Engine.scala:427)
  scala.collection.immutable.List.foreach(List.scala:333)
  org.scalatest.SuperEngine.traverseSubNodes$1(Engine.scala:401)
  org.scalatest.SuperEngine.runTestsInBranch(Engine.scala:396)
  org.scalatest.SuperEngine.runTestsImpl(Engine.scala:475)
  org.scalatest.flatspec.AnyFlatSpecLike.runTests(AnyFlatSpecLike.scala:1900)
  org.scalatest.flatspec.AnyFlatSpecLike.runTests$(AnyFlatSpecLike.scala:1899)
  org.scalatest.flatspec.AnyFlatSpec.runTests(AnyFlatSpec.scala:1686)
  org.scalatest.Suite.run(Suite.scala:1114)
  org.scalatest.Suite.run$(Suite.scala:1096)
  org.scalatest.flatspec.AnyFlatSpec.org$scalatest$flatspec$AnyFlatSpecLike$$super$run(AnyFlatSpec.scala:1686)
  org.scalatest.flatspec.AnyFlatSpecLike.$anonfun$run$1(AnyFlatSpecLike.scala:1945)
  org.scalatest.SuperEngine.runImpl(Engine.scala:535)
  org.scalatest.flatspec.AnyFlatSpecLike.run(AnyFlatSpecLike.scala:1945)
  org.scalatest.flatspec.AnyFlatSpecLike.run$(AnyFlatSpecLike.scala:1943)
  org.scalatest.flatspec.AnyFlatSpec.run(AnyFlatSpec.scala:1686)
  ammonite.$sess.cmd0$Helper.assertPassed(cmd0.sc:5)
  ammonite.$sess.cmd0$Helper.test(cmd0.sc:18)
  ammonite.$sess.cmd18$Helper.<init>(cmd18.sc:7)
  ammonite.$sess.cmd18$.<clinit>(cmd18.sc:7)

Exercise 31.9 (24 points) Implement a function rename that renames variable names in e consistently using the given callback to fresh to generate fresh names for bound variables and env to rename free variable uses.

Edit this cell:

def rename[S](env: Map[String, String], e: Expr)(fresh: String => DoWith[S, String]): DoWith[S, Expr] = {
  def rename(env: Map[String, String], e: Expr): DoWith[S, Expr] = {
    def r(e: Expr) = rename(env, e)
    e match {
      case N(_) => doreturn(e)
      case B(_) =>
        ???

      case Var(x) =>
        ???

      case ConstDecl(x, e1, e2) => fresh(x) flatMap { x_ =>
        ???
      }

      case Unary(uop, e1) =>
        ???

      case Binary(bop, e1, e2) =>
        ???

      case If(e1, e2, e3) =>
        ???

      case Fun(x, (y, t), tret, e1) =>
        ???

      case Call(e1, e2) =>
        r(e1) flatMap { e1 =>
          r(e2) map { e2 => Call(e1, e2) }
        }
    }
  }
  rename(env, e)
}
defined function rename

Notes

  • Hint: Use the given cases for N and Call as models. The only methods for manipulating DoWith objects needed in this exercise are doreturn, map, and flatMap.
  • Accelerated: You may try to use for-yield expressions to replace your map and flatMap calls.

31.3.3 Test

test(new AnyFlatSpec {
 "rename" should "rename in a DoWith" in {
    val e1 = ConstDecl("a", N(1), Var("a"))
    val e1p = ConstDecl("aa", N(1), Var("aa"))

    assertResult( (1, e1p) ) {
      rename(Map.empty, e1){ x => domodify[Int](n => n + 1) map { _ => x + x } }(0)
    }
  }
 }, 4)
Run starting. Expected test count is: 1
cmd20$Helper$$anon$1:
rename
- should rename in a DoWith *** FAILED ***
  scala.NotImplementedError: an implementation is missing
  at scala.Predef$.$qmark$qmark$qmark(Predef.scala:345)
  at ammonite.$sess.cmd13$Helper.domodify(cmd13.sc:2)
  at ammonite.$sess.cmd20$Helper$$anon$1.$anonfun$new$2(cmd20.sc:7)
  at ammonite.$sess.cmd19$Helper.rename$1(cmd19.sc:12)
  at ammonite.$sess.cmd19$Helper.rename(cmd19.sc:34)
  at ammonite.$sess.cmd20$Helper$$anon$1.$anonfun$new$1(cmd20.sc:7)
  at org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85)
  at org.scalatest.OutcomeOf.outcomeOf$(OutcomeOf.scala:83)
  at org.scalatest.OutcomeOf$.outcomeOf(OutcomeOf.scala:104)
  at org.scalatest.Transformer.apply(Transformer.scala:22)
  ...
Run completed in 2 milliseconds.
Total number of tests run: 1
Suites: completed 1, aborted 0
Tests: succeeded 0, failed 1, canceled 0, ignored 0, pending 0
*** 1 TEST FAILED ***
java.lang.AssertionError: assertion failed: an implementation is missing (rename should rename in a DoWith)
  scala.Predef$.assert(Predef.scala:280)
  ammonite.$sess.cmd0$Helper$$anon$1.apply(cmd0.sc:7)
  org.scalatest.WrapperCatchReporter.doApply(CatchReporter.scala:70)
  org.scalatest.CatchReporter.apply(CatchReporter.scala:36)
  org.scalatest.CatchReporter.apply$(CatchReporter.scala:34)
  org.scalatest.WrapperCatchReporter.apply(CatchReporter.scala:63)
  org.scalatest.Suite$.reportTestFailed(Suite.scala:1644)
  org.scalatest.SuperEngine.runTestImpl(Engine.scala:347)
  org.scalatest.flatspec.AnyFlatSpecLike.runTest(AnyFlatSpecLike.scala:1842)
  org.scalatest.flatspec.AnyFlatSpecLike.runTest$(AnyFlatSpecLike.scala:1824)
  org.scalatest.flatspec.AnyFlatSpec.runTest(AnyFlatSpec.scala:1686)
  org.scalatest.flatspec.AnyFlatSpecLike.$anonfun$runTests$1(AnyFlatSpecLike.scala:1900)
  org.scalatest.SuperEngine.$anonfun$runTestsInBranch$1(Engine.scala:413)
  scala.collection.immutable.List.foreach(List.scala:333)
  org.scalatest.SuperEngine.traverseSubNodes$1(Engine.scala:401)
  org.scalatest.SuperEngine.runTestsInBranch(Engine.scala:390)
  org.scalatest.SuperEngine.$anonfun$runTestsInBranch$1(Engine.scala:427)
  scala.collection.immutable.List.foreach(List.scala:333)
  org.scalatest.SuperEngine.traverseSubNodes$1(Engine.scala:401)
  org.scalatest.SuperEngine.runTestsInBranch(Engine.scala:396)
  org.scalatest.SuperEngine.runTestsImpl(Engine.scala:475)
  org.scalatest.flatspec.AnyFlatSpecLike.runTests(AnyFlatSpecLike.scala:1900)
  org.scalatest.flatspec.AnyFlatSpecLike.runTests$(AnyFlatSpecLike.scala:1899)
  org.scalatest.flatspec.AnyFlatSpec.runTests(AnyFlatSpec.scala:1686)
  org.scalatest.Suite.run(Suite.scala:1114)
  org.scalatest.Suite.run$(Suite.scala:1096)
  org.scalatest.flatspec.AnyFlatSpec.org$scalatest$flatspec$AnyFlatSpecLike$$super$run(AnyFlatSpec.scala:1686)
  org.scalatest.flatspec.AnyFlatSpecLike.$anonfun$run$1(AnyFlatSpecLike.scala:1945)
  org.scalatest.SuperEngine.runImpl(Engine.scala:535)
  org.scalatest.flatspec.AnyFlatSpecLike.run(AnyFlatSpecLike.scala:1945)
  org.scalatest.flatspec.AnyFlatSpecLike.run$(AnyFlatSpecLike.scala:1943)
  org.scalatest.flatspec.AnyFlatSpec.run(AnyFlatSpec.scala:1686)
  ammonite.$sess.cmd0$Helper.assertPassed(cmd0.sc:5)
  ammonite.$sess.cmd0$Helper.test(cmd0.sc:18)
  ammonite.$sess.cmd20$Helper.<init>(cmd20.sc:10)
  ammonite.$sess.cmd20$.<clinit>(cmd20.sc:7)
test(new AnyFlatSpec {
  def fresh(s: String): DoWith[Int,String] = doget flatMap { i => doput(i + 1) map { _ => s"x${i}" } }
  def renv(env: Map[String, String], e: Expr): (Int, Expr) = rename(env, e)(fresh)(0)
  def r(e: Expr) = renv(Map.empty, e)

  "rename/B" should "RenameB" in {
    assertResult( (0, B(true)) ) { r(B(true)) }
  }
}, 4)
Run starting. Expected test count is: 1
cmd21$Helper$$anon$1:
rename/B
- should RenameB *** FAILED ***
  scala.NotImplementedError: an implementation is missing
  at scala.Predef$.$qmark$qmark$qmark(Predef.scala:345)
  at ammonite.$sess.cmd19$Helper.rename$1(cmd19.sc:7)
  at ammonite.$sess.cmd19$Helper.rename(cmd19.sc:34)
  at ammonite.$sess.cmd21$Helper$$anon$1.renv(cmd21.sc:3)
  at ammonite.$sess.cmd21$Helper$$anon$1.r(cmd21.sc:4)
  at ammonite.$sess.cmd21$Helper$$anon$1.$anonfun$new$1(cmd21.sc:7)
  at org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85)
  at org.scalatest.OutcomeOf.outcomeOf$(OutcomeOf.scala:83)
  at org.scalatest.OutcomeOf$.outcomeOf(OutcomeOf.scala:104)
  at org.scalatest.Transformer.apply(Transformer.scala:22)
  ...
Run completed in 3 milliseconds.
Total number of tests run: 1
Suites: completed 1, aborted 0
Tests: succeeded 0, failed 1, canceled 0, ignored 0, pending 0
*** 1 TEST FAILED ***
java.lang.AssertionError: assertion failed: an implementation is missing (rename/B should RenameB)
  scala.Predef$.assert(Predef.scala:280)
  ammonite.$sess.cmd0$Helper$$anon$1.apply(cmd0.sc:7)
  org.scalatest.WrapperCatchReporter.doApply(CatchReporter.scala:70)
  org.scalatest.CatchReporter.apply(CatchReporter.scala:36)
  org.scalatest.CatchReporter.apply$(CatchReporter.scala:34)
  org.scalatest.WrapperCatchReporter.apply(CatchReporter.scala:63)
  org.scalatest.Suite$.reportTestFailed(Suite.scala:1644)
  org.scalatest.SuperEngine.runTestImpl(Engine.scala:347)
  org.scalatest.flatspec.AnyFlatSpecLike.runTest(AnyFlatSpecLike.scala:1842)
  org.scalatest.flatspec.AnyFlatSpecLike.runTest$(AnyFlatSpecLike.scala:1824)
  org.scalatest.flatspec.AnyFlatSpec.runTest(AnyFlatSpec.scala:1686)
  org.scalatest.flatspec.AnyFlatSpecLike.$anonfun$runTests$1(AnyFlatSpecLike.scala:1900)
  org.scalatest.SuperEngine.$anonfun$runTestsInBranch$1(Engine.scala:413)
  scala.collection.immutable.List.foreach(List.scala:333)
  org.scalatest.SuperEngine.traverseSubNodes$1(Engine.scala:401)
  org.scalatest.SuperEngine.runTestsInBranch(Engine.scala:390)
  org.scalatest.SuperEngine.$anonfun$runTestsInBranch$1(Engine.scala:427)
  scala.collection.immutable.List.foreach(List.scala:333)
  org.scalatest.SuperEngine.traverseSubNodes$1(Engine.scala:401)
  org.scalatest.SuperEngine.runTestsInBranch(Engine.scala:396)
  org.scalatest.SuperEngine.runTestsImpl(Engine.scala:475)
  org.scalatest.flatspec.AnyFlatSpecLike.runTests(AnyFlatSpecLike.scala:1900)
  org.scalatest.flatspec.AnyFlatSpecLike.runTests$(AnyFlatSpecLike.scala:1899)
  org.scalatest.flatspec.AnyFlatSpec.runTests(AnyFlatSpec.scala:1686)
  org.scalatest.Suite.run(Suite.scala:1114)
  org.scalatest.Suite.run$(Suite.scala:1096)
  org.scalatest.flatspec.AnyFlatSpec.org$scalatest$flatspec$AnyFlatSpecLike$$super$run(AnyFlatSpec.scala:1686)
  org.scalatest.flatspec.AnyFlatSpecLike.$anonfun$run$1(AnyFlatSpecLike.scala:1945)
  org.scalatest.SuperEngine.runImpl(Engine.scala:535)
  org.scalatest.flatspec.AnyFlatSpecLike.run(AnyFlatSpecLike.scala:1945)
  org.scalatest.flatspec.AnyFlatSpecLike.run$(AnyFlatSpecLike.scala:1943)
  org.scalatest.flatspec.AnyFlatSpec.run(AnyFlatSpec.scala:1686)
  ammonite.$sess.cmd0$Helper.assertPassed(cmd0.sc:5)
  ammonite.$sess.cmd0$Helper.test(cmd0.sc:18)
  ammonite.$sess.cmd21$Helper.<init>(cmd21.sc:9)
  ammonite.$sess.cmd21$.<clinit>(cmd21.sc:7)
test(new AnyFlatSpec {
  def fresh(s: String): DoWith[Int,String] = doget flatMap { i => doput(i + 1) map { _ => s"x${i}" } }
  def renv(env: Map[String, String], e: Expr): (Int, Expr) = rename(env, e)(fresh)(0)
  def r(e: Expr) = renv(Map.empty, e)

  "rename/Var" should "RenameVar" in {
    assertResult( (0, Var("y")) ) { renv(Map("x" -> "y"), Var("x")) }
  }
}, 4)
Run starting. Expected test count is: 1
cmd22$Helper$$anon$1:
rename/Var
- should RenameVar *** FAILED ***
  scala.NotImplementedError: an implementation is missing
  at scala.Predef$.$qmark$qmark$qmark(Predef.scala:345)
  at ammonite.$sess.cmd19$Helper.rename$1(cmd19.sc:10)
  at ammonite.$sess.cmd19$Helper.rename(cmd19.sc:34)
  at ammonite.$sess.cmd22$Helper$$anon$1.renv(cmd22.sc:3)
  at ammonite.$sess.cmd22$Helper$$anon$1.$anonfun$new$1(cmd22.sc:7)
  at org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85)
  at org.scalatest.OutcomeOf.outcomeOf$(OutcomeOf.scala:83)
  at org.scalatest.OutcomeOf$.outcomeOf(OutcomeOf.scala:104)
  at org.scalatest.Transformer.apply(Transformer.scala:22)
  at org.scalatest.Transformer.apply(Transformer.scala:20)
  ...
Run completed in 2 milliseconds.
Total number of tests run: 1
Suites: completed 1, aborted 0
Tests: succeeded 0, failed 1, canceled 0, ignored 0, pending 0
*** 1 TEST FAILED ***
java.lang.AssertionError: assertion failed: an implementation is missing (rename/Var should RenameVar)
  scala.Predef$.assert(Predef.scala:280)
  ammonite.$sess.cmd0$Helper$$anon$1.apply(cmd0.sc:7)
  org.scalatest.WrapperCatchReporter.doApply(CatchReporter.scala:70)
  org.scalatest.CatchReporter.apply(CatchReporter.scala:36)
  org.scalatest.CatchReporter.apply$(CatchReporter.scala:34)
  org.scalatest.WrapperCatchReporter.apply(CatchReporter.scala:63)
  org.scalatest.Suite$.reportTestFailed(Suite.scala:1644)
  org.scalatest.SuperEngine.runTestImpl(Engine.scala:347)
  org.scalatest.flatspec.AnyFlatSpecLike.runTest(AnyFlatSpecLike.scala:1842)
  org.scalatest.flatspec.AnyFlatSpecLike.runTest$(AnyFlatSpecLike.scala:1824)
  org.scalatest.flatspec.AnyFlatSpec.runTest(AnyFlatSpec.scala:1686)
  org.scalatest.flatspec.AnyFlatSpecLike.$anonfun$runTests$1(AnyFlatSpecLike.scala:1900)
  org.scalatest.SuperEngine.$anonfun$runTestsInBranch$1(Engine.scala:413)
  scala.collection.immutable.List.foreach(List.scala:333)
  org.scalatest.SuperEngine.traverseSubNodes$1(Engine.scala:401)
  org.scalatest.SuperEngine.runTestsInBranch(Engine.scala:390)
  org.scalatest.SuperEngine.$anonfun$runTestsInBranch$1(Engine.scala:427)
  scala.collection.immutable.List.foreach(List.scala:333)
  org.scalatest.SuperEngine.traverseSubNodes$1(Engine.scala:401)
  org.scalatest.SuperEngine.runTestsInBranch(Engine.scala:396)
  org.scalatest.SuperEngine.runTestsImpl(Engine.scala:475)
  org.scalatest.flatspec.AnyFlatSpecLike.runTests(AnyFlatSpecLike.scala:1900)
  org.scalatest.flatspec.AnyFlatSpecLike.runTests$(AnyFlatSpecLike.scala:1899)
  org.scalatest.flatspec.AnyFlatSpec.runTests(AnyFlatSpec.scala:1686)
  org.scalatest.Suite.run(Suite.scala:1114)
  org.scalatest.Suite.run$(Suite.scala:1096)
  org.scalatest.flatspec.AnyFlatSpec.org$scalatest$flatspec$AnyFlatSpecLike$$super$run(AnyFlatSpec.scala:1686)
  org.scalatest.flatspec.AnyFlatSpecLike.$anonfun$run$1(AnyFlatSpecLike.scala:1945)
  org.scalatest.SuperEngine.runImpl(Engine.scala:535)
  org.scalatest.flatspec.AnyFlatSpecLike.run(AnyFlatSpecLike.scala:1945)
  org.scalatest.flatspec.AnyFlatSpecLike.run$(AnyFlatSpecLike.scala:1943)
  org.scalatest.flatspec.AnyFlatSpec.run(AnyFlatSpec.scala:1686)
  ammonite.$sess.cmd0$Helper.assertPassed(cmd0.sc:5)
  ammonite.$sess.cmd0$Helper.test(cmd0.sc:18)
  ammonite.$sess.cmd22$Helper.<init>(cmd22.sc:9)
  ammonite.$sess.cmd22$.<clinit>(cmd22.sc:7)
test(new AnyFlatSpec {
  def fresh(s: String): DoWith[Int,String] = doget flatMap { i => doput(i + 1) map { _ => s"x${i}" } }
  def renv(env: Map[String, String], e: Expr): (Int, Expr) = rename(env, e)(fresh)(0)
  def r(e: Expr) = renv(Map.empty, e)

  def e(x: String) = ConstDecl(x, N(1), Var(x))
  "rename/ConstDecl" should "RenameConstDecl" in {
    assertResult( (1, e("x0")) ) { r(e("foo")) }
  }
}, 4)
Run starting. Expected test count is: 1
cmd23$Helper$$anon$1:
rename/ConstDecl
- should RenameConstDecl *** FAILED ***
  scala.NotImplementedError: an implementation is missing
  at scala.Predef$.$qmark$qmark$qmark(Predef.scala:345)
  at ammonite.$sess.cmd19$Helper.$anonfun$rename$1(cmd19.sc:13)
  at ammonite.$sess.cmd10$Helper$DoWith.$anonfun$flatMap$1(cmd10.sc:12)
  at ammonite.$sess.cmd10$Helper$DoWith.apply(cmd10.sc:16)
  at ammonite.$sess.cmd23$Helper$$anon$1.renv(cmd23.sc:3)
  at ammonite.$sess.cmd23$Helper$$anon$1.r(cmd23.sc:4)
  at ammonite.$sess.cmd23$Helper$$anon$1.$anonfun$new$1(cmd23.sc:8)
  at org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85)
  at org.scalatest.OutcomeOf.outcomeOf$(OutcomeOf.scala:83)
  at org.scalatest.OutcomeOf$.outcomeOf(OutcomeOf.scala:104)
  ...
Run completed in 4 milliseconds.
Total number of tests run: 1
Suites: completed 1, aborted 0
Tests: succeeded 0, failed 1, canceled 0, ignored 0, pending 0
*** 1 TEST FAILED ***
java.lang.AssertionError: assertion failed: an implementation is missing (rename/ConstDecl should RenameConstDecl)
  scala.Predef$.assert(Predef.scala:280)
  ammonite.$sess.cmd0$Helper$$anon$1.apply(cmd0.sc:7)
  org.scalatest.WrapperCatchReporter.doApply(CatchReporter.scala:70)
  org.scalatest.CatchReporter.apply(CatchReporter.scala:36)
  org.scalatest.CatchReporter.apply$(CatchReporter.scala:34)
  org.scalatest.WrapperCatchReporter.apply(CatchReporter.scala:63)
  org.scalatest.Suite$.reportTestFailed(Suite.scala:1644)
  org.scalatest.SuperEngine.runTestImpl(Engine.scala:347)
  org.scalatest.flatspec.AnyFlatSpecLike.runTest(AnyFlatSpecLike.scala:1842)
  org.scalatest.flatspec.AnyFlatSpecLike.runTest$(AnyFlatSpecLike.scala:1824)
  org.scalatest.flatspec.AnyFlatSpec.runTest(AnyFlatSpec.scala:1686)
  org.scalatest.flatspec.AnyFlatSpecLike.$anonfun$runTests$1(AnyFlatSpecLike.scala:1900)
  org.scalatest.SuperEngine.$anonfun$runTestsInBranch$1(Engine.scala:413)
  scala.collection.immutable.List.foreach(List.scala:333)
  org.scalatest.SuperEngine.traverseSubNodes$1(Engine.scala:401)
  org.scalatest.SuperEngine.runTestsInBranch(Engine.scala:390)
  org.scalatest.SuperEngine.$anonfun$runTestsInBranch$1(Engine.scala:427)
  scala.collection.immutable.List.foreach(List.scala:333)
  org.scalatest.SuperEngine.traverseSubNodes$1(Engine.scala:401)
  org.scalatest.SuperEngine.runTestsInBranch(Engine.scala:396)
  org.scalatest.SuperEngine.runTestsImpl(Engine.scala:475)
  org.scalatest.flatspec.AnyFlatSpecLike.runTests(AnyFlatSpecLike.scala:1900)
  org.scalatest.flatspec.AnyFlatSpecLike.runTests$(AnyFlatSpecLike.scala:1899)
  org.scalatest.flatspec.AnyFlatSpec.runTests(AnyFlatSpec.scala:1686)
  org.scalatest.Suite.run(Suite.scala:1114)
  org.scalatest.Suite.run$(Suite.scala:1096)
  org.scalatest.flatspec.AnyFlatSpec.org$scalatest$flatspec$AnyFlatSpecLike$$super$run(AnyFlatSpec.scala:1686)
  org.scalatest.flatspec.AnyFlatSpecLike.$anonfun$run$1(AnyFlatSpecLike.scala:1945)
  org.scalatest.SuperEngine.runImpl(Engine.scala:535)
  org.scalatest.flatspec.AnyFlatSpecLike.run(AnyFlatSpecLike.scala:1945)
  org.scalatest.flatspec.AnyFlatSpecLike.run$(AnyFlatSpecLike.scala:1943)
  org.scalatest.flatspec.AnyFlatSpec.run(AnyFlatSpec.scala:1686)
  ammonite.$sess.cmd0$Helper.assertPassed(cmd0.sc:5)
  ammonite.$sess.cmd0$Helper.test(cmd0.sc:18)
  ammonite.$sess.cmd23$Helper.<init>(cmd23.sc:10)
  ammonite.$sess.cmd23$.<clinit>(cmd23.sc:7)
test(new AnyFlatSpec {
  def fresh(s: String): DoWith[Int,String] = doget flatMap { i => doput(i + 1) map { _ => s"x${i}" } }
  def renv(env: Map[String, String], e: Expr): (Int, Expr) = rename(env, e)(fresh)(0)
  def r(e: Expr) = renv(Map.empty, e)

  def e(f: String, y: String) = Fun(f, (y, TNumber), TNumber, Call(Var("f"), Var("y")))
  "rename/Fun" should "RenameFun" in {
    assertResult( (2, e("x0", "x1")) ) { r(e("foo", "bar")) }
  }
}, 4)
Run starting. Expected test count is: 1
cmd24$Helper$$anon$1:
rename/Fun
- should RenameFun *** FAILED ***
  scala.NotImplementedError: an implementation is missing
  at scala.Predef$.$qmark$qmark$qmark(Predef.scala:345)
  at ammonite.$sess.cmd19$Helper.rename$1(cmd19.sc:26)
  at ammonite.$sess.cmd19$Helper.rename(cmd19.sc:34)
  at ammonite.$sess.cmd24$Helper$$anon$1.renv(cmd24.sc:3)
  at ammonite.$sess.cmd24$Helper$$anon$1.r(cmd24.sc:4)
  at ammonite.$sess.cmd24$Helper$$anon$1.$anonfun$new$1(cmd24.sc:8)
  at org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85)
  at org.scalatest.OutcomeOf.outcomeOf$(OutcomeOf.scala:83)
  at org.scalatest.OutcomeOf$.outcomeOf(OutcomeOf.scala:104)
  at org.scalatest.Transformer.apply(Transformer.scala:22)
  ...
Run completed in 1 millisecond.
Total number of tests run: 1
Suites: completed 1, aborted 0
Tests: succeeded 0, failed 1, canceled 0, ignored 0, pending 0
*** 1 TEST FAILED ***
java.lang.AssertionError: assertion failed: an implementation is missing (rename/Fun should RenameFun)
  scala.Predef$.assert(Predef.scala:280)
  ammonite.$sess.cmd0$Helper$$anon$1.apply(cmd0.sc:7)
  org.scalatest.WrapperCatchReporter.doApply(CatchReporter.scala:70)
  org.scalatest.CatchReporter.apply(CatchReporter.scala:36)
  org.scalatest.CatchReporter.apply$(CatchReporter.scala:34)
  org.scalatest.WrapperCatchReporter.apply(CatchReporter.scala:63)
  org.scalatest.Suite$.reportTestFailed(Suite.scala:1644)
  org.scalatest.SuperEngine.runTestImpl(Engine.scala:347)
  org.scalatest.flatspec.AnyFlatSpecLike.runTest(AnyFlatSpecLike.scala:1842)
  org.scalatest.flatspec.AnyFlatSpecLike.runTest$(AnyFlatSpecLike.scala:1824)
  org.scalatest.flatspec.AnyFlatSpec.runTest(AnyFlatSpec.scala:1686)
  org.scalatest.flatspec.AnyFlatSpecLike.$anonfun$runTests$1(AnyFlatSpecLike.scala:1900)
  org.scalatest.SuperEngine.$anonfun$runTestsInBranch$1(Engine.scala:413)
  scala.collection.immutable.List.foreach(List.scala:333)
  org.scalatest.SuperEngine.traverseSubNodes$1(Engine.scala:401)
  org.scalatest.SuperEngine.runTestsInBranch(Engine.scala:390)
  org.scalatest.SuperEngine.$anonfun$runTestsInBranch$1(Engine.scala:427)
  scala.collection.immutable.List.foreach(List.scala:333)
  org.scalatest.SuperEngine.traverseSubNodes$1(Engine.scala:401)
  org.scalatest.SuperEngine.runTestsInBranch(Engine.scala:396)
  org.scalatest.SuperEngine.runTestsImpl(Engine.scala:475)
  org.scalatest.flatspec.AnyFlatSpecLike.runTests(AnyFlatSpecLike.scala:1900)
  org.scalatest.flatspec.AnyFlatSpecLike.runTests$(AnyFlatSpecLike.scala:1899)
  org.scalatest.flatspec.AnyFlatSpec.runTests(AnyFlatSpec.scala:1686)
  org.scalatest.Suite.run(Suite.scala:1114)
  org.scalatest.Suite.run$(Suite.scala:1096)
  org.scalatest.flatspec.AnyFlatSpec.org$scalatest$flatspec$AnyFlatSpecLike$$super$run(AnyFlatSpec.scala:1686)
  org.scalatest.flatspec.AnyFlatSpecLike.$anonfun$run$1(AnyFlatSpecLike.scala:1945)
  org.scalatest.SuperEngine.runImpl(Engine.scala:535)
  org.scalatest.flatspec.AnyFlatSpecLike.run(AnyFlatSpecLike.scala:1945)
  org.scalatest.flatspec.AnyFlatSpecLike.run$(AnyFlatSpecLike.scala:1943)
  org.scalatest.flatspec.AnyFlatSpec.run(AnyFlatSpec.scala:1686)
  ammonite.$sess.cmd0$Helper.assertPassed(cmd0.sc:5)
  ammonite.$sess.cmd0$Helper.test(cmd0.sc:18)
  ammonite.$sess.cmd24$Helper.<init>(cmd24.sc:10)
  ammonite.$sess.cmd24$.<clinit>(cmd24.sc:7)
test(new AnyFlatSpec {
  def fresh(s: String): DoWith[Int,String] = doget flatMap { i => doput(i + 1) map { _ => s"x${i}" } }
  def renv(env: Map[String, String], e: Expr): (Int, Expr) = rename(env, e)(fresh)(0)
  def r(e: Expr) = renv(Map.empty, e)

  def factorial(fact: String, n: String) = Fun(fact, (n, TNumber), TNumber,
    If(Binary(Eq, Var(n), N(1)),
    N(1),
    Binary(Times, Var(n), Call(Var(fact), Binary(Plus, Var(n), N(-1)))))
  )

  "rename" should "rename bound variables consistently for factorial" in {
    assertResult( (2, factorial("x0", "x1")) ) { r(factorial("fact", "n")) }
  }

  it should "rename with a different fresh" in {
    assertResult( (4, factorial("fact0", "n2")) ) {
      val e = factorial("fact", "n")
      rename[Int](Map.empty, e)(x => doget flatMap { i => doput(i + 2) map { _ => s"${x}${i}" } })(0)
    }
  }
}, 4)
Run starting. Expected test count is: 2
cmd25$Helper$$anon$1:
rename
- should rename bound variables consistently for factorial *** FAILED ***
  scala.NotImplementedError: an implementation is missing
  at scala.Predef$.$qmark$qmark$qmark(Predef.scala:345)
  at ammonite.$sess.cmd19$Helper.rename$1(cmd19.sc:26)
  at ammonite.$sess.cmd19$Helper.rename(cmd19.sc:34)
  at ammonite.$sess.cmd25$Helper$$anon$1.renv(cmd25.sc:3)
  at ammonite.$sess.cmd25$Helper$$anon$1.r(cmd25.sc:4)
  at ammonite.$sess.cmd25$Helper$$anon$1.$anonfun$new$1(cmd25.sc:13)
  at org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85)
  at org.scalatest.OutcomeOf.outcomeOf$(OutcomeOf.scala:83)
  at org.scalatest.OutcomeOf$.outcomeOf(OutcomeOf.scala:104)
  at org.scalatest.Transformer.apply(Transformer.scala:22)
  ...
- should rename with a different fresh *** FAILED ***
  scala.NotImplementedError: an implementation is missing
  at scala.Predef$.$qmark$qmark$qmark(Predef.scala:345)
  at ammonite.$sess.cmd19$Helper.rename$1(cmd19.sc:26)
  at ammonite.$sess.cmd19$Helper.rename(cmd19.sc:34)
  at ammonite.$sess.cmd25$Helper$$anon$1.$anonfun$new$2(cmd25.sc:19)
  at org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85)
  at org.scalatest.OutcomeOf.outcomeOf$(OutcomeOf.scala:83)
  at org.scalatest.OutcomeOf$.outcomeOf(OutcomeOf.scala:104)
  at org.scalatest.Transformer.apply(Transformer.scala:22)
  at org.scalatest.Transformer.apply(Transformer.scala:20)
  at org.scalatest.flatspec.AnyFlatSpecLike$$anon$5.apply(AnyFlatSpecLike.scala:1832)
  ...
Run completed in 3 milliseconds.
Total number of tests run: 2
Suites: completed 1, aborted 0
Tests: succeeded 0, failed 2, canceled 0, ignored 0, pending 0
*** 2 TESTS FAILED ***
java.lang.AssertionError: assertion failed: an implementation is missing (rename should rename bound variables consistently for factorial)
  scala.Predef$.assert(Predef.scala:280)
  ammonite.$sess.cmd0$Helper$$anon$1.apply(cmd0.sc:7)
  org.scalatest.WrapperCatchReporter.doApply(CatchReporter.scala:70)
  org.scalatest.CatchReporter.apply(CatchReporter.scala:36)
  org.scalatest.CatchReporter.apply$(CatchReporter.scala:34)
  org.scalatest.WrapperCatchReporter.apply(CatchReporter.scala:63)
  org.scalatest.Suite$.reportTestFailed(Suite.scala:1644)
  org.scalatest.SuperEngine.runTestImpl(Engine.scala:347)
  org.scalatest.flatspec.AnyFlatSpecLike.runTest(AnyFlatSpecLike.scala:1842)
  org.scalatest.flatspec.AnyFlatSpecLike.runTest$(AnyFlatSpecLike.scala:1824)
  org.scalatest.flatspec.AnyFlatSpec.runTest(AnyFlatSpec.scala:1686)
  org.scalatest.flatspec.AnyFlatSpecLike.$anonfun$runTests$1(AnyFlatSpecLike.scala:1900)
  org.scalatest.SuperEngine.$anonfun$runTestsInBranch$1(Engine.scala:413)
  scala.collection.immutable.List.foreach(List.scala:333)
  org.scalatest.SuperEngine.traverseSubNodes$1(Engine.scala:401)
  org.scalatest.SuperEngine.runTestsInBranch(Engine.scala:390)
  org.scalatest.SuperEngine.$anonfun$runTestsInBranch$1(Engine.scala:427)
  scala.collection.immutable.List.foreach(List.scala:333)
  org.scalatest.SuperEngine.traverseSubNodes$1(Engine.scala:401)
  org.scalatest.SuperEngine.runTestsInBranch(Engine.scala:396)
  org.scalatest.SuperEngine.runTestsImpl(Engine.scala:475)
  org.scalatest.flatspec.AnyFlatSpecLike.runTests(AnyFlatSpecLike.scala:1900)
  org.scalatest.flatspec.AnyFlatSpecLike.runTests$(AnyFlatSpecLike.scala:1899)
  org.scalatest.flatspec.AnyFlatSpec.runTests(AnyFlatSpec.scala:1686)
  org.scalatest.Suite.run(Suite.scala:1114)
  org.scalatest.Suite.run$(Suite.scala:1096)
  org.scalatest.flatspec.AnyFlatSpec.org$scalatest$flatspec$AnyFlatSpecLike$$super$run(AnyFlatSpec.scala:1686)
  org.scalatest.flatspec.AnyFlatSpecLike.$anonfun$run$1(AnyFlatSpecLike.scala:1945)
  org.scalatest.SuperEngine.runImpl(Engine.scala:535)
  org.scalatest.flatspec.AnyFlatSpecLike.run(AnyFlatSpecLike.scala:1945)
  org.scalatest.flatspec.AnyFlatSpecLike.run$(AnyFlatSpecLike.scala:1943)
  org.scalatest.flatspec.AnyFlatSpec.run(AnyFlatSpec.scala:1686)
  ammonite.$sess.cmd0$Helper.assertPassed(cmd0.sc:5)
  ammonite.$sess.cmd0$Helper.test(cmd0.sc:18)
  ammonite.$sess.cmd25$Helper.<init>(cmd25.sc:22)
  ammonite.$sess.cmd25$.<clinit>(cmd25.sc:7)

Exercise 31.10 (4 points) Finally, implement the lowering-transformation function uniquify: Expr => Expr on closed expressions using a call to rename to rename bound variables consistently with the freshVarWith: String => DoWith[Int, String] function defined above. Start the Int counter-state at 0.

Edit this cell:

def uniquify(e: Expr): Expr = {
  require(isClosed(e), s"$e should be closed")
  ???
}
defined function uniquify

Notes

  • Hint: The rename and freshVarWith functions constructs DoWith objects. The uniquify finally uses a DoWith[Int, String] object. How? By calling it with the initial state 0.

Test

test(new AnyFlatSpec with Matchers with ScalaCheckPropertyChecks {
  def idfun(f: String, y: String) =
    Fun(f, (y, TNumber), TNumber, Var(y))
  def aconst(x1: String, x2: String, x3: String, x4: String, x5: String) =
    ConstDecl(x1, Binary(Plus, Call(idfun(x2, x3), N(1)), Call(idfun(x4, x5), N(2))), Var(x1))
  def nm(x: String, i: Int) = s"${x}_${i}"

  "uniquify" should "work on the example" in {
    forAll { (x1: String, x2: String, x3: String, x4: String, x5: String) =>
      uniquify(aconst(x1, x2, x3, x4, x5)) should be {
        aconst(nm(x1, 0), nm(x2, 1), nm(x3, 2), nm(x4, 3), nm(x5, 4))
      }
    }
  }

  val e = ConstDecl("a", ConstDecl("a", N(1), Var("a")), ConstDecl("b",N(2), Var("b")))
  val exp = ConstDecl("a_0", ConstDecl("a_1", N(1), Var("a_1")), ConstDecl("b_2", N(2), Var("b_2")))
  it should "work another example" in {
    assertResult(exp) { uniquify(e) }
  }
}, 4)
Run starting. Expected test count is: 2
cmd27$Helper$$anon$1:
uniquify
- should work on the example *** FAILED ***
  NotImplementedError was thrown during property evaluation.
    Message: an implementation is missing
    Occurred when passed generated values (
      arg0 = "",
      arg1 = "",
      arg2 = "",
      arg3 = "",
      arg4 = ""
    )
  Init Seed: -4491544589935107168
- should work another example *** FAILED ***
  scala.NotImplementedError: an implementation is missing
  at scala.Predef$.$qmark$qmark$qmark(Predef.scala:345)
  at ammonite.$sess.cmd26$Helper.uniquify(cmd26.sc:3)
  at ammonite.$sess.cmd27$Helper$$anon$1.$anonfun$new$3(cmd27.sc:19)
  at org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85)
  at org.scalatest.OutcomeOf.outcomeOf$(OutcomeOf.scala:83)
  at org.scalatest.OutcomeOf$.outcomeOf(OutcomeOf.scala:104)
  at org.scalatest.Transformer.apply(Transformer.scala:22)
  at org.scalatest.Transformer.apply(Transformer.scala:20)
  at org.scalatest.flatspec.AnyFlatSpecLike$$anon$5.apply(AnyFlatSpecLike.scala:1832)
  at org.scalatest.TestSuite.withFixture(TestSuite.scala:196)
  ...
Run completed in 9 milliseconds.
Total number of tests run: 2
Suites: completed 1, aborted 0
Tests: succeeded 0, failed 2, canceled 0, ignored 0, pending 0
*** 2 TESTS FAILED ***
java.lang.AssertionError: assertion failed: NotImplementedError was thrown during property evaluation.
  Message: an implementation is missing
  Occurred when passed generated values (
    arg0 = "",
    arg1 = "",
    arg2 = "",
    arg3 = "",
    arg4 = ""
  )
Init Seed: 4951171170451891909 (uniquify should work on the example)
  scala.Predef$.assert(Predef.scala:280)
  ammonite.$sess.cmd0$Helper$$anon$1.apply(cmd0.sc:7)
  org.scalatest.WrapperCatchReporter.doApply(CatchReporter.scala:70)
  org.scalatest.CatchReporter.apply(CatchReporter.scala:36)
  org.scalatest.CatchReporter.apply$(CatchReporter.scala:34)
  org.scalatest.WrapperCatchReporter.apply(CatchReporter.scala:63)
  org.scalatest.Suite$.reportTestFailed(Suite.scala:1644)
  org.scalatest.SuperEngine.runTestImpl(Engine.scala:347)
  org.scalatest.flatspec.AnyFlatSpecLike.runTest(AnyFlatSpecLike.scala:1842)
  org.scalatest.flatspec.AnyFlatSpecLike.runTest$(AnyFlatSpecLike.scala:1824)
  org.scalatest.flatspec.AnyFlatSpec.runTest(AnyFlatSpec.scala:1686)
  org.scalatest.flatspec.AnyFlatSpecLike.$anonfun$runTests$1(AnyFlatSpecLike.scala:1900)
  org.scalatest.SuperEngine.$anonfun$runTestsInBranch$1(Engine.scala:413)
  scala.collection.immutable.List.foreach(List.scala:333)
  org.scalatest.SuperEngine.traverseSubNodes$1(Engine.scala:401)
  org.scalatest.SuperEngine.runTestsInBranch(Engine.scala:390)
  org.scalatest.SuperEngine.$anonfun$runTestsInBranch$1(Engine.scala:427)
  scala.collection.immutable.List.foreach(List.scala:333)
  org.scalatest.SuperEngine.traverseSubNodes$1(Engine.scala:401)
  org.scalatest.SuperEngine.runTestsInBranch(Engine.scala:396)
  org.scalatest.SuperEngine.runTestsImpl(Engine.scala:475)
  org.scalatest.flatspec.AnyFlatSpecLike.runTests(AnyFlatSpecLike.scala:1900)
  org.scalatest.flatspec.AnyFlatSpecLike.runTests$(AnyFlatSpecLike.scala:1899)
  org.scalatest.flatspec.AnyFlatSpec.runTests(AnyFlatSpec.scala:1686)
  org.scalatest.Suite.run(Suite.scala:1114)
  org.scalatest.Suite.run$(Suite.scala:1096)
  org.scalatest.flatspec.AnyFlatSpec.org$scalatest$flatspec$AnyFlatSpecLike$$super$run(AnyFlatSpec.scala:1686)
  org.scalatest.flatspec.AnyFlatSpecLike.$anonfun$run$1(AnyFlatSpecLike.scala:1945)
  org.scalatest.SuperEngine.runImpl(Engine.scala:535)
  org.scalatest.flatspec.AnyFlatSpecLike.run(AnyFlatSpecLike.scala:1945)
  org.scalatest.flatspec.AnyFlatSpecLike.run$(AnyFlatSpecLike.scala:1943)
  org.scalatest.flatspec.AnyFlatSpec.run(AnyFlatSpec.scala:1686)
  ammonite.$sess.cmd0$Helper.assertPassed(cmd0.sc:5)
  ammonite.$sess.cmd0$Helper.test(cmd0.sc:18)
  ammonite.$sess.cmd27$Helper.<init>(cmd27.sc:21)
  ammonite.$sess.cmd27$.<clinit>(cmd27.sc:7)

31.3.4 DoWith with Collections

Recall the higher-order function map we considered previously for Lists.

def map[A, B](l: List[A])(f: A => B): List[B] =
  l.foldRight[List[B]](
    Nil
  ) { (h, acc) =>
    f(h) :: acc
  }
defined function map

We may want to use DoWith to encapsulate some stateful computation with other data structures, like Lists. For example, we want a version of map that can take a stateful callback:

Exercise 31.11 (4 points) Implement a function mapWith for List that takes a stateful callback function f: A => DoWith[S, B]:

Edit this cell:

def mapWith[S, A, B](l: List[A])(f: A => DoWith[S, B]): DoWith[S, List[B]] =
  l.foldRight[DoWith[S, List[B]]](
    ???
  ) { (h, acc) =>
    ???
  }
defined function mapWith

Tests

test(new AnyFlatSpec {
  val l = List(1, 2, 3, 4, 5)
  val r1 = l.map { i => i + 1 }

  def dowith1[W]: DoWith[W,List[Int]] = mapWith(l) { i: Int => doreturn(i + 1) }
      
  "mapWith" should "Test1" in { assertResult((true,r1)) { dowith1(true) } }
  it should "Test2" in {assertResult((42,r1)) { dowith1(42) }}
  it should "Test3" in {assertResult((2 * l.length + 1, r1)) {
        val dw: DoWith[Int,List[Int]] = mapWith(l) { i: Int =>
          domodify[Int](s => s + 2) map { _ => i + 1 }
        }
        dw(1)
      }}
}, 4)
Run starting. Expected test count is: 3
cmd30$Helper$$anon$1:
mapWith
- should Test1 *** FAILED ***
  scala.NotImplementedError: an implementation is missing
  at scala.Predef$.$qmark$qmark$qmark(Predef.scala:345)
  at ammonite.$sess.cmd29$Helper.mapWith(cmd29.sc:3)
  at ammonite.$sess.cmd30$Helper$$anon$1.dowith1(cmd30.sc:5)
  at ammonite.$sess.cmd30$Helper$$anon$1.$anonfun$new$1(cmd30.sc:7)
  at org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85)
  at org.scalatest.OutcomeOf.outcomeOf$(OutcomeOf.scala:83)
  at org.scalatest.OutcomeOf$.outcomeOf(OutcomeOf.scala:104)
  at org.scalatest.Transformer.apply(Transformer.scala:22)
  at org.scalatest.Transformer.apply(Transformer.scala:20)
  at org.scalatest.flatspec.AnyFlatSpecLike$$anon$5.apply(AnyFlatSpecLike.scala:1832)
  ...
- should Test2 *** FAILED ***
  scala.NotImplementedError: an implementation is missing
  at scala.Predef$.$qmark$qmark$qmark(Predef.scala:345)
  at ammonite.$sess.cmd29$Helper.mapWith(cmd29.sc:3)
  at ammonite.$sess.cmd30$Helper$$anon$1.dowith1(cmd30.sc:5)
  at ammonite.$sess.cmd30$Helper$$anon$1.$anonfun$new$2(cmd30.sc:8)
  at org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85)
  at org.scalatest.OutcomeOf.outcomeOf$(OutcomeOf.scala:83)
  at org.scalatest.OutcomeOf$.outcomeOf(OutcomeOf.scala:104)
  at org.scalatest.Transformer.apply(Transformer.scala:22)
  at org.scalatest.Transformer.apply(Transformer.scala:20)
  at org.scalatest.flatspec.AnyFlatSpecLike$$anon$5.apply(AnyFlatSpecLike.scala:1832)
  ...
- should Test3 *** FAILED ***
  scala.NotImplementedError: an implementation is missing
  at scala.Predef$.$qmark$qmark$qmark(Predef.scala:345)
  at ammonite.$sess.cmd29$Helper.mapWith(cmd29.sc:3)
  at ammonite.$sess.cmd30$Helper$$anon$1.$anonfun$new$3(cmd30.sc:10)
  at org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85)
  at org.scalatest.OutcomeOf.outcomeOf$(OutcomeOf.scala:83)
  at org.scalatest.OutcomeOf$.outcomeOf(OutcomeOf.scala:104)
  at org.scalatest.Transformer.apply(Transformer.scala:22)
  at org.scalatest.Transformer.apply(Transformer.scala:20)
  at org.scalatest.flatspec.AnyFlatSpecLike$$anon$5.apply(AnyFlatSpecLike.scala:1832)
  at org.scalatest.TestSuite.withFixture(TestSuite.scala:196)
  ...
Run completed in 4 milliseconds.
Total number of tests run: 3
Suites: completed 1, aborted 0
Tests: succeeded 0, failed 3, canceled 0, ignored 0, pending 0
*** 3 TESTS FAILED ***
java.lang.AssertionError: assertion failed: an implementation is missing (mapWith should Test1)
  scala.Predef$.assert(Predef.scala:280)
  ammonite.$sess.cmd0$Helper$$anon$1.apply(cmd0.sc:7)
  org.scalatest.WrapperCatchReporter.doApply(CatchReporter.scala:70)
  org.scalatest.CatchReporter.apply(CatchReporter.scala:36)
  org.scalatest.CatchReporter.apply$(CatchReporter.scala:34)
  org.scalatest.WrapperCatchReporter.apply(CatchReporter.scala:63)
  org.scalatest.Suite$.reportTestFailed(Suite.scala:1644)
  org.scalatest.SuperEngine.runTestImpl(Engine.scala:347)
  org.scalatest.flatspec.AnyFlatSpecLike.runTest(AnyFlatSpecLike.scala:1842)
  org.scalatest.flatspec.AnyFlatSpecLike.runTest$(AnyFlatSpecLike.scala:1824)
  org.scalatest.flatspec.AnyFlatSpec.runTest(AnyFlatSpec.scala:1686)
  org.scalatest.flatspec.AnyFlatSpecLike.$anonfun$runTests$1(AnyFlatSpecLike.scala:1900)
  org.scalatest.SuperEngine.$anonfun$runTestsInBranch$1(Engine.scala:413)
  scala.collection.immutable.List.foreach(List.scala:333)
  org.scalatest.SuperEngine.traverseSubNodes$1(Engine.scala:401)
  org.scalatest.SuperEngine.runTestsInBranch(Engine.scala:390)
  org.scalatest.SuperEngine.$anonfun$runTestsInBranch$1(Engine.scala:427)
  scala.collection.immutable.List.foreach(List.scala:333)
  org.scalatest.SuperEngine.traverseSubNodes$1(Engine.scala:401)
  org.scalatest.SuperEngine.runTestsInBranch(Engine.scala:396)
  org.scalatest.SuperEngine.runTestsImpl(Engine.scala:475)
  org.scalatest.flatspec.AnyFlatSpecLike.runTests(AnyFlatSpecLike.scala:1900)
  org.scalatest.flatspec.AnyFlatSpecLike.runTests$(AnyFlatSpecLike.scala:1899)
  org.scalatest.flatspec.AnyFlatSpec.runTests(AnyFlatSpec.scala:1686)
  org.scalatest.Suite.run(Suite.scala:1114)
  org.scalatest.Suite.run$(Suite.scala:1096)
  org.scalatest.flatspec.AnyFlatSpec.org$scalatest$flatspec$AnyFlatSpecLike$$super$run(AnyFlatSpec.scala:1686)
  org.scalatest.flatspec.AnyFlatSpecLike.$anonfun$run$1(AnyFlatSpecLike.scala:1945)
  org.scalatest.SuperEngine.runImpl(Engine.scala:535)
  org.scalatest.flatspec.AnyFlatSpecLike.run(AnyFlatSpecLike.scala:1945)
  org.scalatest.flatspec.AnyFlatSpecLike.run$(AnyFlatSpecLike.scala:1943)
  org.scalatest.flatspec.AnyFlatSpec.run(AnyFlatSpec.scala:1686)
  ammonite.$sess.cmd0$Helper.assertPassed(cmd0.sc:5)
  ammonite.$sess.cmd0$Helper.test(cmd0.sc:18)
  ammonite.$sess.cmd30$Helper.<init>(cmd30.sc:15)
  ammonite.$sess.cmd30$.<clinit>(cmd30.sc:7)

Also recall the mapFirst function we defined previously that replaces the first element in l where f returns Some(a) with a:

def mapFirst[A](l: List[A])(f: A => Option[A]): List[A] = l match {
  case Nil => Nil
  case h :: t =>
    f(h) match {
      case None => h :: mapFirst(t)(f)
      case Some(h) => h :: t
    }
}
defined function mapFirst

Exercise 31.12 (4 points) Implement a function mapFirstWith for List that instead takes a stateful callback function f: A => Option[DoWith[S, B]]:

Edit this cell:

def mapFirstWith[S, A](l: List[A])(f: A => Option[DoWith[S, A]]): DoWith[S, List[A]] = l match {
  case Nil =>
    ???
  case h :: t =>
    ???
}
defined function mapFirstWith

Tests

test(new AnyFlatSpec {
  val l = List(1, 2, -3, 4, -5)
  val r = List(1, 2, 3, 4, -5)
  def dowith[W]: DoWith[W,List[Int]] = mapFirstWith(l) { (i: Int) => if (i < 0) Some(doreturn(-i)) else None }
      
  val w1 = true
  val w2 = 10
  val w3 = "test_str"
  val w4 = List
      
  "mapFirstWith" should "Test1" in { assertResult((w1,r)){ dowith(w1) } }
  it should "Test2" in {assertResult((w2,r)) { dowith(w2) }}
  it should "Test3" in {assertResult((w3,r)) { dowith(w3) }}
  it should "Test4" in {assertResult((w4,r)) { dowith(w4) }}
}, 4)
Run starting. Expected test count is: 4
cmd33$Helper$$anon$1:
mapFirstWith
- should Test1 *** FAILED ***
  scala.NotImplementedError: an implementation is missing
  at scala.Predef$.$qmark$qmark$qmark(Predef.scala:345)
  at ammonite.$sess.cmd32$Helper.mapFirstWith(cmd32.sc:5)
  at ammonite.$sess.cmd33$Helper$$anon$1.dowith(cmd33.sc:4)
  at ammonite.$sess.cmd33$Helper$$anon$1.$anonfun$new$1(cmd33.sc:11)
  at org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85)
  at org.scalatest.OutcomeOf.outcomeOf$(OutcomeOf.scala:83)
  at org.scalatest.OutcomeOf$.outcomeOf(OutcomeOf.scala:104)
  at org.scalatest.Transformer.apply(Transformer.scala:22)
  at org.scalatest.Transformer.apply(Transformer.scala:20)
  at org.scalatest.flatspec.AnyFlatSpecLike$$anon$5.apply(AnyFlatSpecLike.scala:1832)
  ...
- should Test2 *** FAILED ***
  scala.NotImplementedError: an implementation is missing
  at scala.Predef$.$qmark$qmark$qmark(Predef.scala:345)
  at ammonite.$sess.cmd32$Helper.mapFirstWith(cmd32.sc:5)
  at ammonite.$sess.cmd33$Helper$$anon$1.dowith(cmd33.sc:4)
  at ammonite.$sess.cmd33$Helper$$anon$1.$anonfun$new$2(cmd33.sc:12)
  at org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85)
  at org.scalatest.OutcomeOf.outcomeOf$(OutcomeOf.scala:83)
  at org.scalatest.OutcomeOf$.outcomeOf(OutcomeOf.scala:104)
  at org.scalatest.Transformer.apply(Transformer.scala:22)
  at org.scalatest.Transformer.apply(Transformer.scala:20)
  at org.scalatest.flatspec.AnyFlatSpecLike$$anon$5.apply(AnyFlatSpecLike.scala:1832)
  ...
- should Test3 *** FAILED ***
  scala.NotImplementedError: an implementation is missing
  at scala.Predef$.$qmark$qmark$qmark(Predef.scala:345)
  at ammonite.$sess.cmd32$Helper.mapFirstWith(cmd32.sc:5)
  at ammonite.$sess.cmd33$Helper$$anon$1.dowith(cmd33.sc:4)
  at ammonite.$sess.cmd33$Helper$$anon$1.$anonfun$new$3(cmd33.sc:13)
  at org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85)
  at org.scalatest.OutcomeOf.outcomeOf$(OutcomeOf.scala:83)
  at org.scalatest.OutcomeOf$.outcomeOf(OutcomeOf.scala:104)
  at org.scalatest.Transformer.apply(Transformer.scala:22)
  at org.scalatest.Transformer.apply(Transformer.scala:20)
  at org.scalatest.flatspec.AnyFlatSpecLike$$anon$5.apply(AnyFlatSpecLike.scala:1832)
  ...
- should Test4 *** FAILED ***
  scala.NotImplementedError: an implementation is missing
  at scala.Predef$.$qmark$qmark$qmark(Predef.scala:345)
  at ammonite.$sess.cmd32$Helper.mapFirstWith(cmd32.sc:5)
  at ammonite.$sess.cmd33$Helper$$anon$1.dowith(cmd33.sc:4)
  at ammonite.$sess.cmd33$Helper$$anon$1.$anonfun$new$4(cmd33.sc:14)
  at org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85)
  at org.scalatest.OutcomeOf.outcomeOf$(OutcomeOf.scala:83)
  at org.scalatest.OutcomeOf$.outcomeOf(OutcomeOf.scala:104)
  at org.scalatest.Transformer.apply(Transformer.scala:22)
  at org.scalatest.Transformer.apply(Transformer.scala:20)
  at org.scalatest.flatspec.AnyFlatSpecLike$$anon$5.apply(AnyFlatSpecLike.scala:1832)
  ...
Run completed in 3 milliseconds.
Total number of tests run: 4
Suites: completed 1, aborted 0
Tests: succeeded 0, failed 4, canceled 0, ignored 0, pending 0
*** 4 TESTS FAILED ***
java.lang.AssertionError: assertion failed: an implementation is missing (mapFirstWith should Test1)
  scala.Predef$.assert(Predef.scala:280)
  ammonite.$sess.cmd0$Helper$$anon$1.apply(cmd0.sc:7)
  org.scalatest.WrapperCatchReporter.doApply(CatchReporter.scala:70)
  org.scalatest.CatchReporter.apply(CatchReporter.scala:36)
  org.scalatest.CatchReporter.apply$(CatchReporter.scala:34)
  org.scalatest.WrapperCatchReporter.apply(CatchReporter.scala:63)
  org.scalatest.Suite$.reportTestFailed(Suite.scala:1644)
  org.scalatest.SuperEngine.runTestImpl(Engine.scala:347)
  org.scalatest.flatspec.AnyFlatSpecLike.runTest(AnyFlatSpecLike.scala:1842)
  org.scalatest.flatspec.AnyFlatSpecLike.runTest$(AnyFlatSpecLike.scala:1824)
  org.scalatest.flatspec.AnyFlatSpec.runTest(AnyFlatSpec.scala:1686)
  org.scalatest.flatspec.AnyFlatSpecLike.$anonfun$runTests$1(AnyFlatSpecLike.scala:1900)
  org.scalatest.SuperEngine.$anonfun$runTestsInBranch$1(Engine.scala:413)
  scala.collection.immutable.List.foreach(List.scala:333)
  org.scalatest.SuperEngine.traverseSubNodes$1(Engine.scala:401)
  org.scalatest.SuperEngine.runTestsInBranch(Engine.scala:390)
  org.scalatest.SuperEngine.$anonfun$runTestsInBranch$1(Engine.scala:427)
  scala.collection.immutable.List.foreach(List.scala:333)
  org.scalatest.SuperEngine.traverseSubNodes$1(Engine.scala:401)
  org.scalatest.SuperEngine.runTestsInBranch(Engine.scala:396)
  org.scalatest.SuperEngine.runTestsImpl(Engine.scala:475)
  org.scalatest.flatspec.AnyFlatSpecLike.runTests(AnyFlatSpecLike.scala:1900)
  org.scalatest.flatspec.AnyFlatSpecLike.runTests$(AnyFlatSpecLike.scala:1899)
  org.scalatest.flatspec.AnyFlatSpec.runTests(AnyFlatSpec.scala:1686)
  org.scalatest.Suite.run(Suite.scala:1114)
  org.scalatest.Suite.run$(Suite.scala:1096)
  org.scalatest.flatspec.AnyFlatSpec.org$scalatest$flatspec$AnyFlatSpecLike$$super$run(AnyFlatSpec.scala:1686)
  org.scalatest.flatspec.AnyFlatSpecLike.$anonfun$run$1(AnyFlatSpecLike.scala:1945)
  org.scalatest.SuperEngine.runImpl(Engine.scala:535)
  org.scalatest.flatspec.AnyFlatSpecLike.run(AnyFlatSpecLike.scala:1945)
  org.scalatest.flatspec.AnyFlatSpecLike.run$(AnyFlatSpecLike.scala:1943)
  org.scalatest.flatspec.AnyFlatSpec.run(AnyFlatSpec.scala:1686)
  ammonite.$sess.cmd0$Helper.assertPassed(cmd0.sc:5)
  ammonite.$sess.cmd0$Helper.test(cmd0.sc:18)
  ammonite.$sess.cmd33$Helper.<init>(cmd33.sc:15)
  ammonite.$sess.cmd33$.<clinit>(cmd33.sc:7)