9

I am trying to use >=> (Kleisli arrow) in Scala. As I understand, it composes functions returning monads. Now I am trying it as follows:

scala> val f = {i:Int => Some(i + 1)}
f: Int => Some[Int] = <function1>

scala> val g = {i:Int => Some(i.toString)}
g: Int => Some[String] = <function1>

scala> val h = f >=> g
<console>:15: error: value >=> is not a member of Int => Some[Int]
       val h = f >=> g
                 ^

Why does not it compile ? How to compose f and g with >=> ?

Michael
  • 41,026
  • 70
  • 193
  • 341

1 Answers1

11

There are two problems here. The first is that the inferred types of your functions are too specific. Option is a monad, but Some is not. In languages like Haskell the equivalent of Some isn't even a type—it's just a constructor—but because of the way algebraic data types are encoded in Scala you have to watch out for this issue. There are two easy fixes—either provide the more general type explicitly:

scala> val f: Int => Option[Int] = i => Some(i + 1)
f: Int => Option[Int] = <function1>

scala> val g: Int => Option[String] = i => Some(i.toString)
g: Int => Option[String] = <function1>

Or use Scalaz's handy some, which returns an appropriately typed Some:

scala> val f = (i: Int) => some(i + 1)
f: Int => Option[Int] = <function1>

scala> val g = (i: Int) => some(i.toString)
g: Int => Option[String] = <function1>

The second problem is that >=> isn't provided for plain old monadic functions in Scalaz—you need to use the Kleisli wrapper:

scala> val h = Kleisli(f) >=> Kleisli(g)
h: scalaz.Kleisli[Option,Int,String] = Kleisli(<function1>)

This does exactly what you want—just use h.run to unwrap.

Travis Brown
  • 138,631
  • 12
  • 375
  • 680
  • Thank you ! Great explanation :) I don't fully understand why I need this `Kleisli` wrapper though. Is it just some _technicality_ or really principal thing ? – Michael Feb 09 '14 at 15:28
  • It's a design decision—you could definitely use an implicit class to add `>=>` to any old `A => M[B]`. I could speculate about the reasons for the decision, but that's a better question for the Scalaz mailing list. – Travis Brown Feb 09 '14 at 15:34