Damian Nadales Damian Nadales - 3 months ago 15
Scala Question

Translating this monadic counter from Haskell to Scala

I have defined a monadic counter in Haskell which I'm trying to translate to Scala, failing miserably so far. The problem in a nutshell is about implementing a counter as a state monad, which reads the counter increment constant from the environment, and logs the history of the counter (its sequence of values).

A friend of mine improved upon my solution, and came up with this simple solution:

newtype Counter = Counter Int deriving (Eq)

instance Show Counter where
show (Counter i) = show i

incWith :: MonadState Counter m => Int -> m ()
incWith n = let incCounter n' (Counter i) = Counter $ i + n'
in modify (incCounter n)

inc :: (MonadReader Int m, MonadState Counter m, MonadWriter [Counter] m) => m ()
inc = ask >>= incWith >> get >>= tell . (:[])

compute :: (MonadReader Int m, MonadState Counter m, MonadWriter [Counter] m) => m ()
compute =
local (const 3) $ do
inc
inc
inc
local (const 5) $ do
inc
inc


I've tried without success to code this into Scala + (Cats | ScalaZ). The latest stable version of Cats lacks a
lift
method for
WriterT
. And with
ReaderWriterState
in
Scalaz
I could not figure out in a couple of hours how to use the
local
method. And that's only the begining ...

How this Haskell solution could be translated in a simple and elegant way? (to the extent allowed by the language).

Side note:

I'm still trying to figure out why I need to spend so much time to translate simple solutions from Haskell to Scala + FP libraries (Cats, Scalaz). In Haskell finding the instances and available functions of each type-class is a breeze, in Scala using IntelliJ, GitHub and StackOverflow this takes me days. So I'm wondering what am I doing wrong, and how could I improve this situation.

Answer

If I understood your intentions right, this translates to very easy and comprehensible piece of code:

  import scalaz._
  import Scalaz._
  val SM = ReaderWriterState.rwstMonad[Id, Int, List[String], Counter]

  case class Counter(value: Int)

  def incWith(n: Int): State[Counter, Unit] = for {
    v ← get[Counter]
    _ ← put(Counter(v.value + n))
  } yield ()

  def inc: IRWS[Int, List[String], Counter, Counter, Unit] = for {
    v ← SM.ask
    c ← SM.get
    _ ← SM.tell(List(s"Incrementing $c by $v "))
    _ ← SM.modify(counter ⇒ Counter(counter.value + v))
  } yield ()

  def compute: IRWS[Int, List[String], Counter, Counter, Unit] = {
    for {
      _ <- SM.local[Unit](i ⇒ 3)(for {
        _ ← inc
        _ ← inc
        _ ← inc
      } yield ())
      _ <- SM.local[Unit](i ⇒ 5)(for {
        _ ← inc
        _ ← inc
        _ ← inc
      } yield ())
    } yield ()
  }

  println(incWith(5)(Counter(0)))
  println(inc.run(4, Counter(0)))
  println(compute.run(0, Counter(0)))