Using OptionT.monadTell

108 views
Skip to first unread message

bhericher

unread,
May 15, 2013, 3:29:43 PM5/15/13
to sca...@googlegroups.com
Hi,

Consider the following code :

val log=OptionT.monadTell[Writer,String,Int]


log.some(1).run.run
res2:  (String, Option[Int]) =("",Some(1))

if I want to have a String logged with some(1), I can write :

log.writer("ok",1).run.run
res3:  (String, Option[Int]) = (ok,Some(1))

but what about "None" :

log;none[Int].run.run
res4 : (String, Option[Int]) = ("",None)

but :

log.writer("nok",None).run.run
res5 : (String, Option[None.type]) = (nok,Some(None))

How can I get ("nok",None)?

Thanks

Benoit



Stefan Hoeck

unread,
May 15, 2013, 3:52:24 PM5/15/13
to sca...@googlegroups.com
The following works:
  (log tell "nok" flatMap { _ => log.none[Int] }).run.run

The following should work but doesn't compile due to problems with type inference:

  (loc.tell("nok") >> log.none[Int]).run.run

Cheers, Stefan

bhericher

unread,
May 15, 2013, 4:43:20 PM5/15/13
to sca...@googlegroups.com
Thanks Stefan!

Benoit

bhericher

unread,
May 16, 2013, 2:24:23 PM5/16/13
to sca...@googlegroups.com
I am trying to developp a generic logger with OptionT.monadTell

So far, it looks (at least for me!) not so bad :

import scalaz._
import Scalaz._

object LoggerOption {
    def Logger[M:Monoid,A] = OptionT.monadTell[Writer,M,A]
    def Write[M:Monoid,A](l : M , oi : Option[A]) = oi match {
            case Some(i) => Logger[M,A].writer(l,i)
            case None => Logger[M,A] tell l flatMap { _ => Logger[M,A].none[A] }
            }
   
}

I can do things like these :

println(LoggerOption.Write(List("No Int"),none:Option[Int]).run.run)
println(LoggerOption.Write(List("Some Int"),Some(6)).run.run)
println(LoggerOption.Write("No Char",none:Option[Char]).run.run)
println(LoggerOption.Write(8,Some('a')).run.run)

and even :

sealed trait ErrorLevel
case object INFO extends ErrorLevel
case object WARNING extends ErrorLevel
case object FATAL extends ErrorLevel



case class MyError (val Level : ErrorLevel, val Message : String)

   

def dummy(i : Int) =  if ( i < 0) LoggerOption.Write(List(MyError(FATAL,"Negative number provided")),none:Option[Int]) else
                            if (i % 2 == 0)  LoggerOption.Write(List(MyError(INFO,"Some even Int provided")),Some(i)) else 
                                    LoggerOption.Write(List(MyError(WARNING,"Some odd Int provided => Incremented")),Some(i+1))
println(dummy(-1).run.run)
println(dummy(6).run.run)
println(dummy(5).run.run)

So far so good.

Now let's consider those two lists :

val lnok = List(2,3,-1,4)
val lok = List(0,5,6)

I traversing them with dummy should produce a Writer with written-part being a List accumulating all the logs and value-part a Option[List[Int]] accumulating all the results :

println(lnok.traverseU(dummy(_)))
println(lok.traverseU(dummy(_)))

But it doesn't compile :

 Unable to unapply type `scalaz.OptionT[[+α]scalaz.Writer[List[Test.MyError],α],Int]` into a type constructor of kind `M[_]` that is classified by the type class `scalaz.Applicative`
1) Check that the type class is defined by compiling `implicitly[scalaz.Applicative[<type constructor>]]`.
2) Review the implicits in object Unapply, which only cover common type 'shapes'
(implicit not found: scalaz.Unapply[scalaz.Applicative, scalaz.OptionT[[+α]scalaz.Writer[List[Test.MyError],α],Int]])
       println(lnok.traverseU(dummy(_)))
                             ^

It seems that something is missing in Unapply.scala. I first assumed that something was wrong with the class MyError, but I get the same messages if I use a simple string.

Any idea?

Thanks

Benoit

PS : Feel free to give your advice on the whole code!

Stefan Hoeck

unread,
May 16, 2013, 5:50:21 PM5/16/13
to sca...@googlegroups.com
Hi Benoit

The compiler needs some help with type inference since it cannot convert the complex return type of function `dummy` into something of kind * -> *. In such cases it can help to use type aliases. First, I'll use DList instead of List for logging accumulation since it has constant time append time complexity:

  type Errors = DList[MyError]
  type DLWriter[+A] = Writer[Errors,A]
  type OLogger[+A] = OptionT[DLWriter,A]

  def write[A](log: Errors, oi: Option[A]): OLogger[A] = ??? //your implementation of LoggerOption.Write as given in your email goes here

Note the return type of `write`. This is important, because the returned type is of kind * -> * which is exactly what you need for list traversal.

Same goes for dummy:
 
  def dummy(i: Int): OLogger[Int] = ??? //your implementation of dummy

Now list traversal compiles out of the box:

  List(1, 2, 3, 4) traverse dummy

Cheers, Stefan

bhericher

unread,
May 17, 2013, 2:22:25 AM5/17/13
to sca...@googlegroups.com
Thanks again for your help

Cheers

Benoit


Le mercredi 15 mai 2013 21:29:43 UTC+2, bhericher a écrit :
Reply all
Reply to author
Forward
0 new messages