Peter Becich (2) [Avatar] Offline
#1
Hello,

I'm confused by the "Next" type in chapter 8. How might I add some type bounds for clarification?

In frdomain.ch8.cqrs.service.AccountService:

  private implicit def liftEvent[Next <: Account](event: Event[Next]): Command[Next] = liftF(event) 
compiles.

However, none of these type bounds compile in frdomain.ch8.cqrs.lib. Just three guesses:

 trait Event[+Next <: Free[Event, Aggregate]] {
  def at: DateTime
}

frdomain.ch8.cqrs.lib.Event's type parameters do not match type S's expected parameters:
type Next's bounds <: scalaz.Free[frdomain.ch8.cqrs.lib.Event,frdomain.ch8.cqrs.lib.Aggregate] are stricter than type _'s declared bounds >: Nothing <: Any
trait Event[+Next <: Free[Event, Aggregate]] {
                                 ^


where type "S" presumably refers to "S" in "class Free[S[_], A]".
From
  type Command[A] = Free[Event, A] 

, S =:= Event.

 trait Event[+Next <: Aggregate] {
  def at: DateTime
}


trait Event[+Next <: Event[_]] {
  def at: DateTime
}



Am I going about this in completely the wrong way? It's a terrific book. Thank you
Debasish Ghosh (116) [Avatar] Offline
#2
May be I am missing something. When do u get the compilation error ? When I try the following, it gives green .. Currently all is in 1 project - I have plans of refactoring though ..


Apples-MacBook-Pro:frdomain debasishg$ sbt
[info] Loading global plugins from /Users/debasishg/.sbt/0.13/plugins
[info] Loading project definition from /Users/debasishg/projects/frdomain/project
[info] Set current project to FRDomain (in build file:/Users/debasishg/projects/frdomain/)
> clean
[success] Total time: 2 s, completed 7 Feb, 2016 12:11:49 AM
> compile
[info] Updating {file:/Users/debasishg/projects/frdomain/}FRDomain...
[info] Resolving jline#jline;2.12.1 ...
[info] Done updating.
[info] Compiling 112 Scala sources to /Users/debasishg/projects/frdomain/target/scala-2.11/classes...
[success] Total time: 51 s, completed 7 Feb, 2016 12:12:43 AM


Thanks.
Peter Becich (2) [Avatar] Offline
#3
Hello, thanks for your response.

The code from your repository definitely compiles. I am just confused by the "Next" parameter. When I try to add some type bounds, I think it breaks compilation.
Debasish Ghosh (116) [Avatar] Offline
#4
The key thing to note is that in the definition of Free in scalaz we have

abstract class Free[S[_], A] { //..


This means S is the existential parameter and the compiler automatically puts a bound <: Any >: Nothing. An existential type means that the exact type is not known - it can be anything and code that depends on existentials also cannot assume any restriction there. Have a look here (http://www.artima.com/pins1ed/combining-scala-and-java.html#29.3).

I guess you cannot restrict it here ..

Thanks.
arya (7) [Avatar] Offline
#5
Hi Debasish, I am excited about the book (and am recommending it to others) but I just reached Chapter 8 myself and I noticed the implementation in Section 8.4 (specifically the chaining with Next) is kind of messed up (no offense!). Notice how the `next` members feel like they are only there to conform to the template? (and why doesn't Opened need to take a Next as input when all the others do?) They aren't needed after all. smilie

So first, the S[_] in Free[S[_], A] is not an existential type, but a higher-kinded type, another case of Scala using _ to mean too many different things in different contexts:
e.g.:
val foo: S[_] = ??? // existential type
class Foo[S[_]] { /* */ } // higher-kinded type


But back to Free interpreters. In:

case class AccountNo(string: String) extends AnyVal

sealed trait Event[A] // #1
case class Opened(no: AccountNo, name: String, openingDate: Option[Date]) extends Event[AccountNo] // #2
case class Closed(no: AccountNo, closeDate: Option[Date]) extends Event[Unit]
case class Debited(no: AccountNo, amount: Amount) extends Event[Unit]
case class Credited(no: AccountNo, amount: Amount) extends Event[Unit] // #3

  val composite =
    for {
      n <- open("a-123", "debasish ghosh", Some(today)) // #4
      _ <- credit(n, 10000) // #5
      _ <- credit(n, 30000)
      _ <- debit(n, 23000)
    } yield (())


#1 an Event[A] represents a command that will return an A
#2 Opened will return an AccountNo, so it extends Event[AccountNo]
#3 Credited will return Unit, so it extends Event[Unit]
#4 calling open(...) produces an AccountNo, which we bind to n
#5 calling credit(...) produces unit, which we discard by binding to _

We can utilize the "free functor" instead of defining our own Functor (and introducing `next` just to give us something to map over) by using Free.liftFC instead of Free.liftF (even in scalaz 7.1) and then we can use Free.runFC to interpret the program according to a NaturalTransformation from Command to State.

I uploaded a complete example at https://github.com/debasishg/frdomain/pull/28

Let me know if you want to chat more, and keep up the good work!


arya (7) [Avatar] Offline
#6
P.S. Side benefit of not having an onInit function in Opened is that now all of the Event classes can be persisted directly!
Debasish Ghosh (116) [Avatar] Offline
#7
Thanks for the PR. I was planning to add the Natural Transformation and CoYoneda bit in the next round of changes. Initially I was not sure if I should speak about NT or CY - You made my life easier.

Thanks.
bhericher (34) [Avatar] Offline
#8
Do you plan to show the use of a library like Freek or eff-cats?

Thank you

Benoit
Debasish Ghosh (116) [Avatar] Offline
#9
I am planning to have some examples as part of the online repository, NOT as part of the core book. Let's see.