Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scala: Bad inferred type for Option composed with StateT monad transformer

I'm somewhat familiar with Haskell monad transformers, but new to Scalaz (version 7). I made (what I thought was) a straightforward translation from the following Haskell code:

import Control.Monad.State

type Pass a = StateT String Maybe a

monadTest :: Pass String
monadTest = do
    s <- get
    return s

to this Scala code:

import scalaz._
import Scalaz._

object StateTest {
  type Pass[A] = StateT[Option, String, A]

  def monadTest: Pass[String] =
    for {
      s <- get[String]
    } yield s
}

The Haskell code compiles. The Scala fails to compile, with the following error:

[error] .../StateTest.scala:9: type mismatch;
[error]  found   : scalaz.IndexedStateT[scalaz.Id.Id,String,String,String]
[error]  required: StateTest.Pass[String]
[error]     (which expands to)  scalaz.IndexedStateT[Option,String,String,String]
[error]       s <- get[String]
[error]         ^

First, it seems scalaz implements StateT in terms of IndexedStateT. Ok. But, it seems that the get[String] monadic value is inferred to have type StateT[Id, String, String] instead of StateT[Option, String, String]. Why?

I'm using Scala 2.10.1, scalaz 7.0.0.

like image 956
alanlcode Avatar asked Apr 28 '13 22:04

alanlcode


1 Answers

In your example, the call to get[String] is calling the get method of StateFunctions, reproduced here:

def get[S]: State[S, S] = init

Where State[S, A] is an alias for StateT[Id, S, A] which is an alias for IndexedStateT[Id, S, S, A].

Because you are using StateT, you need to call get on an instance of StateTMonadState[S, F], or StateTMonadState[String, Option] in your case. The working example is:

import scalaz._
import Scalaz._

object StateTest {
  type Pass[A] = StateT[Option, String, A]

  val sm = StateT.stateTMonadState[String, Option]

  def monadTest: Pass[String] =
    for {
      s <- sm.get
    } yield s
}

The MonadState instance can also be resolved implicitly via MonadState[F[_, _], S] but it is less convenient to use due to the type lambda required. See MonadState.scala and StateT.scala for more info.

like image 77
mpilquist Avatar answered Nov 11 '22 11:11

mpilquist