Why does PureScript traceM print strings from previous values? - purescript

In ghci with the same steps I get:
λ> bar
hello
Just 500
but with pulp repl I get this instead:
> bar
'hi'
'hello'
(Just 500)
Full session:
> import Debug.Trace (traceM)
> import Data.Maybe
> :paste
… foo :: Maybe Int
… foo = do
… traceM "hi"
… Just 5
…
> foo
'hi'
(Just 5)
> :paste
… bar :: Maybe Int
… bar = do
… traceM "hello"
… Just 500
…
> bar
'hi'
'hello'
(Just 500)

Related

Purescript - How to define function signature in REPL?

When I type, say:
f :: Int -> Int
The REPL complaints with:
The type declaration for f should be followed by its definition.
The REPL expects each single line to be a complete program, and since a lonely signature is not a complete program, you get an error.
In order to make the REPL ingest several lines before trying to compile them, use the :paste command to begin the block and then hit Ctrl+D to end it:
> :paste
… f :: Int -> Int
… f x = x + 42
… ^D
> f 1
43
This and other commands can be discovered by typing :?, as the REPL invites you to do at the beginning of the session:
PSCi, version 0.13.6
Type :? for help

Leave out parentheses in method call

I am writing a DSL in Scala where I'd like to achieve a chain of method calls as follows:
def x(i:Int) = i
x 1 equals 1 //doesn't compile
I am not sure why the compiler is happy if I leave out the second parentheses but not the first one:
x(1) equals 1 //works fine
Is there a way to achieve the first version?
You can invoke methods without parenthesis, but not functions.
So the following works:
scala> object Foo {
| def x(i:Int) = i
| }
defined object Foo
scala> Foo x 1
res9: Int = 1
scala> Foo x 1 equals 1
res10: Boolean = true

Scala - unexpected type switch from Map to Iterable in for comprehension?

I'm confused by the typing going on behind the scenes in for comprehensions over maps. My understanding is that the outer collection type is usually supposed to be preserved, and we see that expected behavior in the following two cases:
scala> for {
| (k,v) <- Map(0->1,2->3)
| } yield k -> v
res0: scala.collection.immutable.Map[Int,Int] = Map(0 -> 1, 2 -> 3)
scala> for {
| (k,v) <- Map(0->1,2->3)
| foo = 1
| } yield k -> v
res1: scala.collection.immutable.Map[Int,Int] = Map(0 -> 1, 2 -> 3)
But when I add a second assignment inside the for comprehension I get something surprising:
scala> for {
| (k,v) <- Map(0->1,2->3)
| foo = 1
| bar = 2
| } yield k -> v
res2: scala.collection.immutable.Iterable[(Int, Int)] = List((0,1), (2,3))
Why is this happening?
If you run scala -Xprint:typer -e "for { ... } yield k->v", you can get a de-sugared version of the code. Here is a very much simplified version of what you get:
val m: Map[Int,Int] = Map(0->1, 2->3)
m.map {
case x # (k,v) =>
val foo = 1
val bar = 2
(x, foo, bar)
}.map {
case ((k,v), foo, bar) => (k, v)
}
So what you'll notice is that when the for-comprehension gets converted to a .map call, it's actually returning foo and bar along with k->v, which means it's a Tuple3[(Int,Int), Int, Int]. Since an iterable of Tuple3 objects can't be turned into a Map, it assumes it must return an Iterable. However, in order to get the correct output, which is a collection of Tuple2 objects, it performs a secondary .map that discards foo and bar from the Tuple3, but at this point it no longer knows that it should have been a Map because when you chain calls to .map that information doesn't get carried forward.
Your example with only one assignment just gets lucky because the intermediate representation is Tuple2[(Int,Int), Int].
On the other hand, if you use a .map directly, it works:
Map(0->1, 2->3).map {
case (k,v) =>
val foo = 1
val bar = 2
k -> v
}

How do chain commands in Scala interpreter?

In windows batch, you chain commands with && operator. How do you do the same in scala interpreter? It looks stupid that I need :load file and call import mainobj._ after every load. Obviously, you want to chain them into one liner.
You could write multiple statements in one line of Scala with ;
scala> val a:Int = 3; val b:Int = 4; println(a+b);
7
a: Int = 3
b: Int = 4
Or first type { then write your commands line by line finishing with }
scala> {
| val x:Int = 1
| val y:Int = 2
| println(x + y)
| }
3
Or you can use :paste to turn on paste mode, and then enter your code.
scala> :paste
// Entering paste mode (ctrl-D to finish)
if (true)
print("that was true")
else
print("false")
// Exiting paste mode, now interpreting.
that was true

Scala for ( ) vs for { }

I'm trying to understand for comprehensions in Scala, and I have a lot of examples that I sort of understand...
One thing I'm having a hard time figuring out is for ( ) vs for { }. I've tried both, and it seems like I can do one thing in one but it breaks in the other.
For example, this does NOT work:
def encode(number: String): Set[List[String]] =
if (number.isEmpty) Set(List())
else {
for (
split <- 1 to number.length
word <- wordsForNum(number take split)
rest <- encode(number drop split)
) yield word :: rest
}.toSet
However, if you change it to { }, it does compile:
def encode(number: String): Set[List[String]] =
if (number.isEmpty) Set(List())
else {
for {
split <- 1 to number.length
word <- wordsForNum(number take split)
rest <- encode(number drop split)
} yield word :: rest
}.toSet
These examples are from a Coursera class I'm taking. The professor didn't mention the "why" in the video & I was wondering if anyone else knows.
Thanks!
From the syntax in the spec, it might seem that parens and braces are interchangeable:
http://www.scala-lang.org/files/archive/spec/2.11/06-expressions.html#for-comprehensions-and-for-loops
but because the generators are separated by semis, the following rules kick in:
http://www.scala-lang.org/files/archive/spec/2.11/01-lexical-syntax.html#newline-characters
I have read and understood that section in the past, from which I vaguely recall the gist that newlines are enabled in the braces, which is to say, a newline char is taken as nl which serves as a semi.
So you can put the generators on separate lines instead of using semicolons.
This is the usual "semicolon inference" that lets you not write semicolons as statement terminators. So the newline in the middle of the generator is not taken as a semi, for instance:
scala> for (c <-
| List(1,2,3)
| ) yield c+1
res0: List[Int] = List(2, 3, 4)
scala> for { c <-
| List(1,2,3)
| i = c+1
| } yield i
res1: List[Int] = List(2, 3, 4)
In Scala () are usually for when you only have one statement. Something like this would have worked:
def encode(number: String): Set[Int] =
if (number.isEmpty) Set()
else {
for (
split <- 1 to number.length // Only one statement in the comprehension
) split
}.toSet
Add one more and it would fail to compile. The same is true for map for example
OK
List(1,2,3).map(number =>
number.toString
)
Not OK (have to use curly braces)
List(1,2,3).map(number =>
println("Hello world")
number.toString
)
Why that is. I have no idea :)