estatico / scala-newtype

NewTypes for Scala with no runtime overhead
Apache License 2.0
540 stars 31 forks source link

using the newtype in the companion #34

Closed fommil closed 6 years ago

fommil commented 6 years ago

I'd like to do something like the following, which is a fully compilable version of http://degoes.net/articles/effects-without-transformers

But if I change the value class encoding for @newtype, I get a compile error

[error] stateio.scala:23:49: class type required but stateio.FastState.StateTask.Type[A] found
[error]               def from[X](fa: Task[X])    = new StateTask(fa)
[error]                                                 ^
import scalaz._, Scalaz._, ioeffect._
import Isomorphism._
import io.estatico.newtype.macros.newtype

object FastState extends SafeApp {
  final class StateTask[A](val io: Task[A]) extends AnyVal
  object StateTask {

    def create[S](initial: S): Task[MonadState[StateTask, S]] =
      for {
        ref <- IORef(initial)
      } yield
        new MonadState[StateTask, S] with IsomorphismMonad[StateTask, Task] {
          override val G: Monad[Task] = Monad[Task]
          override val iso: StateTask <~> Task =
            new IsoFunctorTemplate[StateTask, Task] {
              def to[X](ga: StateTask[X]) = ga.io
              def from[X](fa: Task[X])    = new StateTask(fa)
            }

          override def get: StateTask[S] = new StateTask(ref.read)
          override def put(s: S): StateTask[Unit] =
            new StateTask(ref.write(s))

          override def init = get
        }
  }

  def program[F[_]](implicit F: MonadState[F, Int]): F[String] =
    for {
      orig   <- F.get
      update = orig + 10
      _      <- F.put(update)
    } yield update.toString

  def app: Task[Unit] =
    for {
      stateMonad <- StateTask.create(10)
      output     <- program(stateMonad).io
      _          <- console.putStrLn(output).widenError[Throwable]
    } yield ()

  def run(@unused args: List[String]): IO[Void, ExitStatus] =
    app.attempt.map(_ => ExitStatus.ExitNow(0))
}
carymrobbins commented 6 years ago

You can't use new with newtype since it's not a class. Instead, use @newtype case class so you get a generated .apply method, or you can use @newtype class and define your own .apply method in the companion. Seems like it should work then, although I haven't fully gone through this code.