Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

stacking StateT in scalaz

I'm trying to understand Monad Transformers in Scala by porting some examples from this tutorial by Dan Piponi: http://blog.sigfpe.com/2006/05/grok-haskell-monad-transformers.html

I did a couple of easy ones:

import Control.Monad.State
import Control.Monad.Identity

test1 = do
    a <- get
    modify (+1)
    b <- get
    return (a,b)

test2 = do
    a <- get
    modify (++"1")
    b <- get
    return (a,b)

go1 = evalState test1 0
go2 = evalState test2 "0" 

becomes:

import scalaz._, Scalaz._

val test1 = for {
  a <- get[Int]
  _ <- modify[Int](1+)
  b <- get
} yield (a,b)

val test2 = for {
  a <- get[String]
  _ <- modify[String](_ + "1")
  b <- get
} yield (a,b)

val go1 = test1.eval(0)
val go2 = test2.eval("0")

But how the heck can I port this next example to Scala?

test3 = do
    modify (+ 1)
    lift $ modify (++ "1")
    a <- get
    b <- lift get
    return (a,b)

go3 = runIdentity $ evalStateT (evalStateT test3 0) "0"

I've gotten this far using scalaz 7.1.0-M6:

type SST[F[_],A] = StateT[F,String,A]
type IST[F[_],A] = StateT[F,Int,A]

val p1: StateT[Id,Int,Unit] = modify[Int](1+)
val p2: StateT[Id,String,Unit] = modify[String](_ + "1")
val p3: StateT[({type l[a]=StateT[Id,String,a]})#l,Int,Unit] = p2.liftM[IST]

but that's not even close yet, and may even be backwards for all I can tell.

Of course I can do this:

import scalaz.Lens._
val test3 = for {
  _ <- firstLens[Int,String] lifts (modify (1+))
  _ <- secondLens[Int,String] lifts (modify (_ + "1"))
  a <- firstLens[Int,String] lifts get
  b <- secondLens[Int,String] lifts get
} yield (a,b)

val go3 = test3.eval(0,"0")

but then I'm not using stacked StateT at all, so it doesn't answer the question.

Thanks in advance!

like image 630
arya Avatar asked May 06 '14 05:05

arya


People also ask

What is a stack in Scala?

A stack is a data structure that follows the last-in, first-out (LIFO) principle. We can add or remove element only from one end called top. Scala has both mutable and immutable versions of a stack. import scala.collection.mutable.Stack var s = Stack [type] () // OR var s = Stack (val1, val2, val3, ...)

What is Scalaz in Scala?

Welcome to Scalaz 7.3 Scalaz is a Scala library for functional programming. It provides purely functional data structures to complement those from the Scala standard library. It defines a set of foundational type classes (e.g. Functor, Monad) and corresponding instances for a large number of data structures. Getting started

How do I make a stack mutable in Scala?

Scala has both mutable and immutable versions of a stack. import scala.collection.mutable.Stack var s = Stack [type] () // OR var s = Stack (val1, val2, val3, ...) Once stack has been created we can either push elements to the stack or pop them out of the stack.

Who is responsible for the development of Scalaz?

Scalaz is designed and developed by Scalaz contributors View on GitHub © 2018 Scalaz Maintainers


1 Answers

The problem is that the modify you get with the usual imports is from State, and isn't going to help you with StateT.

It's a good idea to start with the Haskell type signature:

test3
  :: (MonadState [Char] m, MonadState s (t m), MonadTrans t,
      Num s) =>
     t m (s, [Char])

Which you should be able to translate into something like this:

import scalaz._, Scalaz._

def test3[M[_]: Monad](implicit
  inner: MonadState[({ type T[s, a] = StateT[M, s, a] })#T, String],
  outer: MonadState[
    ({
      type T[s, a] = StateT[({ type L[y] = StateT[M, String, y] })#L, s, a ]
    })#T,
    Int
  ],
  mt: MonadTrans[({ type L[f[_], a] = StateT[f, Int, a] })#L]
) = for {
  _ <- outer.modify(_ + 1)
  _ <- mt.liftMU(inner.modify(_ + "1"))
  a <- outer.get
  b <- mt.liftMU(inner.get)
} yield (a, b)

It's hideous, but it's a fairly straightforward rewording of the Haskell. For some reason the compiler doesn't seem to find the outer instance, though, so you have to help it a little:

def test3[M[_]: Monad](implicit
  inner: MonadState[({ type T[s, a] = StateT[M, s, a] })#T, String],
  mt: MonadTrans[({ type L[f[_], a] = StateT[f, Int, a] })#L]
) = {
  val outer =
    StateT.stateTMonadState[Int, ({ type L[y] = StateT[M, String, y] })#L]

  for {
    _ <- outer.modify(_ + 1)
    _ <- mt.liftMU(inner.modify(_ + "1"))
    a <- outer.get
    b <- mt.liftMU(inner.get)
  } yield (a, b)
}

Now you can write the following, for example:

scala> test3[Id].eval(0).eval("0")
res0: (Int, String) = (1,01)

Exactly as in the Haskell example.

Footnote

You can clean this up a bit if you're happy with committing to Id as the monad of the inner state transformer (as your comment suggests):

def test3 = {
  val mt = MonadTrans[({ type L[f[_], a] = StateT[f, Int, a] })#L]
  val outer = StateT.stateTMonadState[Int, ({ type L[y] = State[String, y] })#L]
  for {
    _ <- outer.modify(_ + 1)
    _ <- mt.liftMU(modify[String](_ + "1"))
    a <- outer.get
    b <- mt.liftMU(get[String])
  } yield (a, b)
}

It's a little less generic, but it may work for you.

like image 177
Travis Brown Avatar answered Oct 02 '22 07:10

Travis Brown