How to trace values of a recursive PureScript function in the repl? - purescript

With this Main.purs (excluding imports):
main :: Effect Unit
main = pure foo
foo :: Unit
foo = trace "foo" (\_ -> unit)
This works as expected with both pulp repl and pulp run:
> import Main
> foo
'foo'
unit
> :q
See ya!
$ pulp run
* Building project in ...
* Build successful.
'foo'
$
But with this Main.purs I get different results with pulp repl and pulp run:
main :: Effect Unit
main = pure $ bar unit
bar :: Unit -> Unit
bar _ = trace "bar" (\_ -> bar unit)
pulp repl:
> import Main
> bar unit
console.js:168
if (isStackOverflowError(e))
^
pulp run:
$ pulp run
* Building project in ...
* Build successful.
'bar'
'bar'
... omitted ...
'bar'
'bar'
'bar'
console.js:168
if (isStackOverflowError(e))
^
I also discovered this odd behavior which may or may not be related:
Main.purs:
main :: Effect Unit
main = pure unit
-- foo is dead code
foo :: Unit
foo = trace "foo" (\_ -> unit)
Shell:
$ pulp run
* Building project in ...
* Build successful.
'foo'

Related

Wrap argThat in a named function

Say I have something like this (VERY OVER-SIMPLIFIED):
case class Foo(bar: String)
val mockFnThatTakesFoo = mock[Foo => Unit]
def fooHasBarSetTo(expectedBar: String, foo: Foo): Boolean = {
val actualBar = foo.bar
actualBar shouldEqual expectedBar
true
}
mockFnThatTakesFoo(argThat(fooHasBarSetTo("blah", _))) wasCalled once
This works. However, the assertion itself is a little bit convoluted and it could be made more readable.
I tried this:
val withFooHavingBarSetTo = (expectedBar: String) => argThat(fooHasBarSetTo(expectedBar, _))
//and then
mockFnThatTakesFoo(withFooHavingBarSetTo("blah")) wasCalled once
Much neater! but doesn't work :/
> [info] FooSpec:
[info] - should do stuff *** FAILED ***
[info] org.mockito.exceptions.misusing.InvalidUseOfMatchersException: Invalid use of argument matchers!
[info] 1 matchers expected, 2 recorded:
[info] -> at com.foo.FooSpec.argThat(FooSpec.scala:28)
[info] -> at com.foo.FooSpec.$anonfun$new$5(FooSpec.scala:204)
Any idea how can this be done?
I believe Mockito is implemented using macro and it tracks positions where argThat and other Mockito methods are placed. For example if you try to create a variable like
val blahBar = argThat(fooHasBarSetTo("blah", _))
You will get an exception "Misplaced or misused argument matcher detected here". So it is impossible to return argThat matcher from another method.
If you need to reuse mock matcher with different argument value I see only one possible solution like
def mockCalledOnceWithFooHavingBar(expectedBar: String) {
mockFnThatTakesFoo(argThat(fooHasBarSetTo(expectedBar, _))) wasCalled once
}
mockCalledOnceWithFooHavingBar("blah")
mockCalledOnceWithFooHavingBar("bar")

Type checker phases

I noticed that the type checker works by phases. Sometimes scalac returns only a few errors, which makes you think that are almost there, but once you fix them all – boom – next phases, you suddenly get a lot of errors that where not there before.
What are the different phases of the type checker?
Is there a way to know in which phase the type checker gave up on my code (other than recognizing the errors)?
As #Felix points out, this answer lists the compile phases:
$ scalac -version
Scala compiler version 2.11.6 -- Copyright 2002-2013, LAMP/EPFL
$ scalac -Xshow-phases
phase name id description
---------- -- -----------
parser 1 parse source into ASTs, perform simple desugaring
namer 2 resolve names, attach symbols to named trees
packageobjects 3 load package objects
typer 4 the meat and potatoes: type the trees
patmat 5 translate match expressions
superaccessors 6 add super accessors in traits and nested classes
extmethods 7 add extension methods for inline classes
pickler 8 serialize symbol tables
refchecks 9 reference/override checking, translate nested objects
uncurry 10 uncurry, translate function values to anonymous classes
tailcalls 11 replace tail calls by jumps
specialize 12 #specialized-driven class and method specialization
explicitouter 13 this refs to outer pointers
erasure 14 erase types, add interfaces for traits
posterasure 15 clean up erased inline classes
lazyvals 16 allocate bitmaps, translate lazy vals into lazified defs
lambdalift 17 move nested functions to top level
constructors 18 move field definitions into constructors
flatten 19 eliminate inner classes
mixin 20 mixin composition
cleanup 21 platform-specific cleanups, generate reflective calls
delambdafy 22 remove lambdas
icode 23 generate portable intermediate code
jvm 24 generate JVM bytecode
terminal 25 the last phase during a compilation run
Is there a way to know in which phase the type checker gave up on my code (other than recognizing the errors)?
If you add the -verbose flag to scalac, it will print the name of each phase and how long it took after that phase completes. You can then infer which phase failed
I don't think that scalac exposes different phases of typing, only the compile phases. The typer is listed as a single compile phase.
The compiler option for this is -Yissue-debug. It outputs a stack trace in 2.10 when an error is issued.
The code supporting it was removed in 2.11 during the refactor of reporting, but the option is still valid. (I restored it at some point because, in fact, it's the quickest way to see what is emitting an error; but apparently that PR died on the vine and disappeared. Probably a victim of push -f.)
In 2.12, you can supply a custom reporter that does just about the same thing. They claim that they will augment the reporter API with access to context, so you could perhaps directly query the current phase, inspect trees, and so on.
Here's an example of the situation you describe:
class C { def f: Int ; def g: Int = "" ; def h = "\000" }
There are three errors, but only one is reported at a time because they are emitted in different compiler phases.
To clarify the question, various phases besides "typer" can create and typecheck trees, and additionally can enforce well-typedness even after trees are typed. (There are also other kinds of errors, such as "unable to write the output file.")
For C, the parser emits an error (under -Xfuture) for the deprecated octal syntax, the typer reports the type mismatch in g, and the grab bag refchecks phase checks the declared but undefined (empty) member f. You would normally wind up fixing one error at a time. If the parser error is emitted as a warning, then the warning would be suppressed until the errors were fixed, so that would be the last to pop up instead of the first.
Here is a sample reporter that tries to do more than output huge stack traces.
package myrep
import scala.tools.nsc.Settings
import scala.tools.nsc.reporters.ConsoleReporter
import scala.reflect.internal.util._
class DebugReporter(ss: Settings) extends ConsoleReporter(ss) {
override def warning(pos: Position, msg: String) = debug {
super.warning(pos, msg)
}
override def error(pos: Position, msg: String) = debug {
super.error(pos, msg)
}
// let it ride
override def hasErrors = false
private def debug(body: => Unit): Unit = {
val pkgs = Set("nsc.ast.parser", "nsc.typechecker", "nsc.transform")
def compilerPackages(e: StackTraceElement): Boolean = pkgs exists (e.getClassName contains _)
def classname(e: StackTraceElement): String = (e.getClassName split """\.""").last
if (ss.Yissuedebug) echo {
((new Throwable).getStackTrace filter compilerPackages map classname).distinct mkString ("Issued from: ", ",", "\n")
}
body
}
}
It lies about having no errors so that the compiler won't abort early.
It would be invoked this way, with the reporter class on the "tool class path":
scalacm -toolcp repdir -Xreporter myrep.DebugReporter -Yissue-debug -deprecation errs.scala
where
$ scalacm -version
Scala compiler version 2.12.0-M2 -- Copyright 2002-2013, LAMP/EPFL
Sample output:
Issued from: Scanners$UnitScanner,Scanners$Scanner,Parsers$Parser,Parsers$Parser$$anonfun$templateStat$1,Parsers$Parser$$anonfun$topStat$1,Parsers$SourceFileParser,Parsers$UnitParser,SyntaxAnalyzer,SyntaxAnalyzer$ParserPhase
errs.scala:4: warning: Octal escape literals are deprecated, use \u0000 instead.
class C { def f: Int ; def g: Int = "" ; def h = "\000" }
^
Issued from: Contexts$ImmediateReporter,Contexts$ContextReporter,Contexts$Context,ContextErrors$ErrorUtils$,ContextErrors$TyperContextErrors$TyperErrorGen$,Typers$Typer,Analyzer$typerFactory$$anon$3
errs.scala:4: error: type mismatch;
found : String("")
required: Int
class C { def f: Int ; def g: Int = "" ; def h = "\000" }
^
Issued from: RefChecks$RefCheckTransformer,Transform$Phase
errs.scala:4: error: class C needs to be abstract, since method f is not defined
class C { def f: Int ; def g: Int = "" ; def h = "\000" }
^
one warning found
two errors found

can't run .scala file from REPL?

I'm newly at Scala.
I want to run function which is wrote at my file while.scala:
def whileLoop {
var i = 1
while(i <= 3) {
println(i)
i += 1
}
}
whileLoop
here is how it looks at REPL:
scala> scala /home/nazar/Downloads/while.scala
<console>:1: error: illegal start of simple expression
If I understood right from book. I need to specify .scala file location and run with:
scala /path/to/file.scala
Why it fails?
Here is snippet from book:
You can run the code like this:
batate$ scala code/scala/while.scala
1
2
3
UPDATE:
I tried options :load it works, but when I want to run another file for_loop.scala:
def forLoop {
println( "for loop using Java-style iteration" )
for(i <- 0 until args.length) {
println(args(i))
}
}
forLoop
it fails:
scala> :load /home/nazar/Downloads/for_loop.scala
Loading /home/nazar/Downloads/for_loop.scala...
<console>:9: error: not found: value args
for(i <- 0 until args.length) {
^
<console>:8: error: not found: value forLoop
forLoop
^
scala> :load /home/nazar/Downloads/for_loop.scala hello scala
That file does not exist
How to solve this trouble?
You do it like this, from the shell / command line, not from within the REPL (% is nominal shell prompt):
% scala MyScalaScriptName.scala
You did this:
% scala
scala> scala while.scala
<console>:1: error: illegal start of simple expression
The only thing known within the Scala REPL is Scala code itself and a few built-in special commands. However, one of them will do what you want:
% cd
% scala
scala> :load Downloads/while.scala
Loading Downloads/while.scala
1
2
3
In order to use command line arguments (via args) it is needed to extend App or more commonly to define a principal or main method in an object, namely a def main(args: Array[String]) method, which defines an entry point to the program. Consider for instance
object AnyName extends App {
def forLoop {
println( "for loop using Java-style iteration" )
for(i <- 0 until args.length) {
println(args(i))
}
}
forLoop
}
AnyName.main(Array("first","second"))
Try to load it from REPL. The other approach is thus,
object AnyName {
def main(args: Array[String]) {
println( "for loop using Java-style iteration" )
for(i <- 0 until args.length) {
println(args(i))
}
}
}
AnyName.main(Array("first","second"))
In this latter example, note the scope of args, bound to the parameter in main.

Specs2 sequential keyword

When I run tests in Junit, their ordering isn't guaranteed. By default, specs2 runs the examples in parallel so ordering isn't guaranteed here as well. However, if I add the sequential keyword, the tests are executed (at least from what it seems) in order. Is there a way to get the sequential behavior but have the examples run in random order?
You can use the latest specs2 2.3-SNAPSHOT version with the random command-line argument (or args.execute(random=true) inside the specification):
class TestSpec extends Specification { def is = s2"""
test1 $e1
test2 $e2
test3 $e3
"""
def e1 = { "starting e1".pp; Thread.sleep(30); "e1".pp; ok }
def e2 = { "starting e2".pp; Thread.sleep(20); "e2".pp; ok }
def e3 = { "starting e3".pp; Thread.sleep(40); "e3".pp; ok }
}
sbt> testOnly *TestSpec* -- random
starting e3
e3
starting e2
e2
starting e1
e1
[info] TestSpec
[info]
[info] + test1
[info] + test2
[info] + test3
[info]
How about decorating/wrapping the test cases with code that acquires a lock at the beginning of each test case? Hacky perhaps, but should work reliably and be easy to implement, until/unless you can find a more meant-to-be-used alternative.

Compile time type tracing

Is it possible to add some magic construct around a Scala expression so that it prints the type during compilation? E.g. have some class, magic function, meta programming type, which does:
val i = 1
Some(11).map(Trace(_ + 1))
// compile
// prints: Int
Not exactly, but how 'bout this
$ cat Test.scala
def Trace[T] = identity[T] _
val i = 1
Some(11) map {x => Trace(x + 1)}
$ scala -Xprint:typer Test.scala 2>&1 | egrep --o 'Trace\[.*\]'
Trace[T >: Nothing <: Any]
Trace[Int]
The first Trace comes from the definition of Trace and can be ignored. The same parameter (-Xprint:typer) works with scalac, too.
If things get really nasty, you can use this:
scala -Xprint:typer -Xprint-types
Gets difficult to read, but tells you exactly what the compiler is thinking.
Something like this will work at runtime
def Type[T](x:T):T = {println(x.asInstanceOf[AnyRef].getClass()); x }
No, there's no such thing. A compiler plugin might be able to do it.