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._defreport(suite: Suite):Unit= suite.execute(stats =true)defassertPassed(suite: Suite):Unit= suite.run(None,Args(new Reporter {defapply(e:Event)= e match{case e @ (_: TestFailed)=>assert(false,s"${e.message} (${e.testName})")case _ =>()}}))defpassed(points:Int):Unit={require(points >=0)if(points ==1)println("*** ๐ Tests Passed (1 point) ***")elseprintln(s"*** ๐ Tests Passed ($points points) ***")}deftest(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 functionreport
defined functionassertPassed
defined functionpassed
defined functiontest
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{===}\):
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 // tcaseobject TNumber extends Typ // t ::= numbercaseobject TBool extends Typ // t ::= boolcaseclassTFun(yt:(String,Typ), tret: Typ)extends Typ // t ::= (y: t) => trettrait Expr // ecaseclassVar(x:String)extends Expr // e ::= xcaseclassConstDecl(x:String, e1: Expr, e2: Expr)extends Expr // e ::= const x = e1; e2caseclassN(n:Double)extends Expr // e ::= ncaseclassUnary(uop: Uop, e1: Expr)extends Expr // e ::= uop e1caseclassBinary(bop: Bop, e1: Expr, e2: Expr)extends Expr // e ::= e1 bop b2caseclassB(b:Boolean)extends Expr // e ::= bcaseclassIf(e1: Expr, e2: Expr, e3: Expr)extends Expr // e ::= e1 ? e2 : e3caseclassFun(x:String, yt:(String, Typ), tret: Typ, e1: Expr)extends Expr // e ::= x(y: t): tret => e1caseclassCall(e1: Expr, e2: Expr)extends Expr // e ::= e1(e2)trait Uop // uopcaseobject Neg extends Uop // uop ::= -caseobject Not extends Uop // uop ::= !trait Bop // bopcaseobject Plus extends Bop // bop ::= *caseobject Times extends Bop // bop ::= *caseobject Eq extends Bop // bop ::= ===deffreeVars(e: Expr):Set[String]= e match{caseVar(x)=>Set(x)caseConstDecl(x, e1, e2)=>freeVars(e1)|(freeVars(e2)- x)caseN(_)|B(_)=>Set.emptycaseUnary(_, e1)=>freeVars(e1)caseBinary(_, e1, e2)=>freeVars(e1)|freeVars(e2)caseIf(e1, e2, e3)=>freeVars(e1)|freeVars(e2)|freeVars(e3)caseFun(x,(y, _), _, e1)=>freeVars(e1)- x - ycaseCall(e1, e2)=>freeVars(e1)|freeVars(e2)}defisClosed(e: Expr):Boolean=freeVars(e).isEmpty
defined traitTyp
defined objectTNumber
defined objectTBool
defined classTFun
defined traitExpr
defined classVar
defined classConstDecl
defined classN
defined classUnary
defined classBinary
defined classB
defined classIf
defined classFun
defined classCall
defined traitUop
defined objectNeg
defined objectNot
defined traitBop
defined objectPlus
defined objectTimes
defined objectEq
defined functionfreeVars
defined functionisClosed
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:
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:
defhastype(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\)
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:
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,
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
defined classStaticTypeError
defined functionhastype
defined functioninferType
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 ***
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 ***
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 ***
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 ***
test(new AnyFlatSpec {val e1 =Binary(Times,Var("i"),N(3))deffun(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 ***
test(new AnyFlatSpec {val e1 =Binary(Times,Var("i"),Call(Var("f"),N(3)))deffun(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 ***
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 ***
defined classDoWith
defined objectDoWithimport 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 functiondoreturn
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 ***
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 functiondomodify
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 ***
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
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:
deffreshVar(x:String):Int=>(Int,String)={ i =>???}
defined functionfreshVar
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:
deffreshVarWith(x:String): DoWith[Int,String]=???
defined functionfreshVarWith
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.
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 {deffresh(s:String): DoWith[Int,String]= doget flatMap { i =>doput(i +1) map { _ =>s"x${i}"}}defrenv(env:Map[String,String], e: Expr):(Int, Expr)=rename(env, e)(fresh)(0)defr(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 ***
test(new AnyFlatSpec {deffresh(s:String): DoWith[Int,String]= doget flatMap { i =>doput(i +1) map { _ =>s"x${i}"}}defrenv(env:Map[String,String], e: Expr):(Int, Expr)=rename(env, e)(fresh)(0)defr(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 ***
test(new AnyFlatSpec {deffresh(s:String): DoWith[Int,String]= doget flatMap { i =>doput(i +1) map { _ =>s"x${i}"}}defrenv(env:Map[String,String], e: Expr):(Int, Expr)=rename(env, e)(fresh)(0)defr(e: Expr)=renv(Map.empty, e)defe(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 ***
test(new AnyFlatSpec {deffresh(s:String): DoWith[Int,String]= doget flatMap { i =>doput(i +1) map { _ =>s"x${i}"}}defrenv(env:Map[String,String], e: Expr):(Int, Expr)=rename(env, e)(fresh)(0)defr(e: Expr)=renv(Map.empty, e)defe(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 ***
test(new AnyFlatSpec {deffresh(s:String): DoWith[Int,String]= doget flatMap { i =>doput(i +1) map { _ =>s"x${i}"}}defrenv(env:Map[String,String], e: Expr):(Int, Expr)=rename(env, e)(fresh)(0)defr(e: Expr)=renv(Map.empty, e)deffactorial(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 ***
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:
defuniquify(e: Expr): Expr ={require(isClosed(e),s"$e should be closed")???}
defined functionuniquify
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 {defidfun(f:String, y:String)=Fun(f,(y, TNumber), TNumber,Var(y))defaconst(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))defnm(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.4DoWith 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 functionmap
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 functionmapWith
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 ***
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 => Nilcase h :: t =>f(h)match{caseNone=> h ::mapFirst(t)(f)caseSome(h)=> h :: t}}
defined functionmapFirst
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 functionmapFirstWith
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))elseNone}val w1 =trueval w2 =10val 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 ***