Just trying to complete an exercise for flattening nested Lists which can contain Ints, nested Lists, or null.
This is easy to do with List[Any] but I was wondering if it's possible to get compile-time checking on the inputs/test values.
So test case
flatten(List(0, 2, List(List(2, 3), 8, List(List(100)), null, List(List(null))), -2))
should be(List(0, 2, 2, 3, 8, 100, -2))
But I'd want a test with (say) a String in it to fail compilation.
flatten(List(0, 2, List(List(2, 3), 8, List(List(100)), "null", List(List(null))), -2))
// should not compile
So I wrote this
object FlattenArray:
type NestedList[T] = Int | List[NestedList[_]] | Null
def flatten(xs: NestedList[_]): List[Int] =
xs match
case (x: Int) :: tail => x :: flatten(tail)
case (ys: List[_]) :: tail => flatten(ys) ::: flatten(tail)
case null :: tail => flatten(tail)
case Nil => Nil
case _ => throw new IllegalArgumentException("This should never happen")
Which does work in the first and fail compilation as expected in the second test case, but rather than a graceful error message, I get a stack overflow:
[error] java.lang.StackOverflowError
[error] dotty.tools.dotc.core.Types$Type.dealias1(Types.scala:1369)
[error] dotty.tools.dotc.core.Types$Type.dealias(Types.scala:1387)
[error] dotty.tools.dotc.typer.ImplicitRunInfo$$anon$1.apply(Implicits.scala:744)
[error] dotty.tools.dotc.core.Types$TypeMap.op$proxy16$1(Types.scala:5246)
[error] dotty.tools.dotc.core.Types$TypeMap.mapArgs(Types.scala:5246)
[error] dotty.tools.dotc.core.Types$TypeMap.mapOver(Types.scala:5281)
[error] dotty.tools.dotc.typer.ImplicitRunInfo$$anon$1.apply(Implicits.scala:750)
[error] dotty.tools.dotc.core.Types$TypeMap.mapOver(Types.scala:5345)
[error] dotty.tools.dotc.typer.ImplicitRunInfo$$anon$1.apply(Implicits.scala:750)
[error] dotty.tools.dotc.core.Types$TypeMap.mapOver(Types.scala:5345)
[error] dotty.tools.dotc.typer.ImplicitRunInfo$$anon$1.apply(Implicits.scala:750)
<repeat last 8 lines ad infinitum>
So my questions are:
Am I doing this right?? (Unsure in particular about the type parameter in the type declaration.) Is there a better way to achieve the compile time type check?
Is this Scala 3's expected failure mode?
Related
Hi I am trying to execute a for comprehension like
(for {
player <- playerRepository.findById(playerId) // findById returns EitherT[Future, String, Player]
teamOpt <- teamRepository.findByPlayer(playerId) // findByPlayer returns EitherT[Future, String, Option[Team]]
playedMatches <- teamOpt.map(team => playedMatchesRepository.findByTeamId(team.id)) // findByTeamId returns EitherT[Future, String, Seq[PlayedMatches]]
} yield (
player,
teamOpt,
playedMatches
)).fold(
error => {
logger.error(s"all error: $error")
Left(error)
},
tuple => {
logger.debug(s"get success -> $tuple")
Right(playerDetailResponse(tuple._1, tuple._2, tuple._3))
}
)
I can not get a corret structure for
playedMatches <- teamOpt.map(team => playedMatchesRepository.findByTeamId(team.id))
I am getting the following error when I compile the project
[error] /Users/agusgambina/code/soccer/app/services/impl/PlayerServiceImpl.scala:28:17: type mismatch;
[error] found : Option[(models.Player, Option[models.Team], cats.data.EitherT[scala.concurrent.Future,String,Seq[models.PlayedMatches]])]
[error] required: cats.data.EitherT[scala.concurrent.Future,?,?]
[error] playedMatches <- teamOpt.map(team => playedMatchesRepository.findByTeamId(team.id))
[error] ^
[error] one error found
I tried to wrap
playedMatches <- teamOpt.map(team => playedMatchesRepository.findByTeamId(team.id)) // findByTeamId returns EitherT[Future, String, Seq[PlayedMatches]]
in here, you are getting an Option[EitherT[Future, String, Seq[PlayedMatches]]] which doesn't compose with the EitherT[Future, String, ???] you are using as Monad for the for comprehension.
one option you have is to actually use a fold on teamOpt.
teamOpt.fold(EitherT(Future.successful(Left("Team not Found"): Either[String, Team]))){ team => playedMatchesRepository.findByTeamId(team.id) }
This way you unwrap the Option with the error case if is empty or the success case if non-empty. (create a function that takes the teamOPt as parameter and the for-comprehension will look much better)
Hope it helps
update
In case of the empty case be successful, and be happy returning an empty sequence:
teamOpt.fold(
EitherT(Future.successful(Right(Seq()): Either[String, Seq[PlayedMatches]))
){ team =>
playedMatchesRepository.findByTeamId(team.id)
}
After upgrading from specs 2.4.13 to 3.7.1
"foo" should {
"bar" >> prop((i: Int) =>
i % 50 must be>= 0
)
}
no longer compiles. It fails with
type mismatch;
[error] found : org.specs2.specification.core.Fragment
[error] required: org.specs2.matcher.Matcher[String]
[error] "bar" >> prop((i: Int) =>
[error] ^
Changing it to
"foo" >> {
"bar" >> prop((i: Int) =>
i % 50 must be>= 0
)
}
will allow it to compile and pass.
Has the behaviour of should been changed?
I don't get such error in 3.8.8. However this might be the result of should being used for a block of examples and should as a matcher construct (a should be_>=(0)).
You can remove the latter usage by mixing-in org.specs2.matcher.NoShouldExpectations
My feeble Scala skills have me baffled about the right way to do something. The code below compiles (and works) only when I include the t match {... line. If I eliminate that line and of course, the diagnostic println on the preceding line, I get the compile time error as shown. Apparently the compiler regards the return of the fold as Unit (surprise to me). That might be reasonable, but I don't understand it. Would someone please enlighten me about a better way to code this, and perhaps give me more insight?
[error] /home/bill/activator/cherry/app/controllers/Application.scala:34: type mismatch;
[error] found : Unit
[error] required: play.api.mvc.Result
[error] }
[error] ^
Source:
def ptweets = Action { implicit request =>
import play.api.data._
val rqForm = Form(Forms.mapping(
"k" -> Forms.number,
"who" -> Forms.text,
"what" -> Forms.text)(TweetInquiry.apply)(TweetInquiry.unapply))
val t = rqForm.bindFromRequest.fold(
formWithErrors => BadRequest("That's not good"),
rq => Ok((views.html.properForm("POST tweets TBD.")(Html("<em>Blah</em>"))))
) // expect a play.api.mvc.Result
println(t.getClass.getName) // this confirms it in both run-time cases
t match { case v:Result => v } // yet this is required for compile
}
as m-z said in the comments, change
val t = rqForm.bindFromRequest.fold(
formWithErrors => BadRequest("That's not good"),
rq => Ok((views.html.properForm("POST tweets TBD.")(Html("<em>Blah</em>"))))
) // expect a play.api.mvc.Result
println(t.getClass.getName) // this confirms it in both run-time cases
t match { case v:Result => v } // yet this is required for compile
to just:
rqForm.bindFromRequest.fold(
formWithErrors => BadRequest("That's not good"),
rq => Ok((views.html.properForm("POST tweets TBD.")(Html("<em>Blah</em>"))))
)
The fold is evaluating to a Result, but in the code you posted, you're assigning that Result to the value t. Thus, instead of the Action block evaluating to the result of the fold, it's evaluating to an assignment (which is Unit, see here).
I was watching this video by Daniel Spiewak and tried to implement sample about Higher Kinds from it. Here's what I get:
/* bad style */
val map: Map[Option[Any], List[Any]] = Map (
Some("foo") -> List("foo", "bar", "baz"),
Some(42) -> List(1, 1, 2, 3, 5, 8),
Some(true) -> List(true, false, true, false)
)
val xs: List[String] =
map(Some("foo")).asInstanceOf[List[String]] // ugly cast
val ys: List[Int] =
map(Some(42)).asInstanceOf[List[Int]] // another one
println(xs)
println(ys)
/* higher kinds usage */
// HOMAP :: ((* => *) x (* => *)) => *
class HOMap[K[_], V[_]](delegate: Map[K[Any], V[Any]]) {
def apply[A](key: K[A]): V[A] =
delegate(key.asInstanceOf[K[Any]]).asInstanceOf[V[A]]
}
object HOMap {
type Pair[K[_], V[_]] = (K[A], V[A]) forSome { type A }
def apply[K[_], V[_]](tuples: Pair[K, V]*) =
new HOMap[K, V](Map(tuples: _*))
}
val map_b: HOMap[Option, List] = HOMap[Option, List](
Some("foo") -> List("foo", "bar", "baz"),
Some(42) -> List(1, 1, 2, 3, 5, 8),
Some(true) -> List(true, false, true, false)
)
val xs_b: List[String] = map_b(Some("foo"))
val ys_b: List[Int] = map_b(Some(42))
println(xs_b)
println(ys_b)
Unfortunately launching this I get the type mismatch error:
username#host:~/workspace/scala/samples$ scala higher_kinds.scala
/home/username/workspace/scala/samples/higher_kinds.scala:30: error: type mismatch;
found : Main.$anon.HOMap.Pair[K,V]*
required: Seq[(K[Any], V[Any])]
new HOMap[K, V](Map(tuples: _*))
^
one error found
My questions:
How can I fix this? I fully understand that I just need to pass in the right type, but my experience with this kind of stuff in Scala is poor and I can't figure out this.
Why this happens? I mean the operation tuples: _* is probably used widely for passing to Map, but it somehow gives some strange type - Main.$anon.HOMap.Pair[K,V]* and not what it's supposed to give.
Why that example is no longer work? Maybe some recent changes to Scala language changed some syntax?
Thanks for answers!
Problem in type varince conditions. In line def apply[K[_], V[_]] you need guaranty that containers K[_] & V[_] can be cast to K[Any] & V[Any]
Just add type covarince constraint (+) to K & V containers:
object HOMap {
def apply[K[+_], V[+_]](tuples: (Pair[K[A], V[A]] forSome { type A })*) =
new HOMap[K, V](Map(tuples: _*))
}
I'm around trying to understand how "Menu.param" works with 2 params
I'm using this code as an example:
https://github.com/dpp/starting_point/blob/menu_fun/src/main/scala/code/snippet/AThread.scala
But I can not make it work
object APost {
// Create a menu for /user/santo
val menu = Menu.param[( User, Posts )]("ParamId1", "ParamId2",
{
case User(p1) :: Posts(p2) :: Nil =>
Full( (p1, p2) )
case _ =>
Empty
},
params => List(params._1.id.toString,params._2.id.toString)) / * / * >> LocGroup("UserPost")
lazy val loc = menu.toLoc
def render = "*" #> loc.currentValue.map(_.docId)
}
When compiling sends me the following error:
[error] /menu2params/src/main/scala/code/snippet/APost.scala:23: constructor cannot be instantiated to expected type;
[error] found : scala.collection.immutable.::[B]
[error] required: String
[error] case ParamId1(p1) :: ParamId1(p2) :: Nil =>
[error] ^
[error] one error found
[error] (compile:compile) Compilation failed
Someone who can help me please
Here is the copy of my project:
https://github.com/hectorgool/menu2params/blob/master/src/main/scala/code/snippet/APost.scala
Thanks for your attention
Menu.param is for use with a single parameter, hence the error requiring a String instead of a List. Menu.params allows you to specify multiple parameters in a list. Making that change to your code should resolve the issue.