4

This is a followup to my previous question

Kleisli defines two operators <=< (compose) and >=> (andThen). The >=> looks very natural for me and I don't understand how <=< can be useful.

Moreover, it looks like there is no >=> semigroup for A => M[A] but the <=< semigroup does exist.

What is the rationale behind it ?

Community
  • 1
  • 1
Michael
  • 41,026
  • 70
  • 193
  • 341
  • 1
    I suspect the only real answer is mathematical tradition. The two are equivalent in that `a <=< b == b >=> a`, no? So it's just a convention, like e.g. matrix multiplication being defined as row-column rather than column-row. – lmm Jul 14 '15 at 14:42

1 Answers1

7

compose (or <=<) is a little more natural when translating between point-free and non point-free styles. For example, if we have these functions:

val f: Int => Int = _ + 1
val g: Int => Int = _ * 10

We get the following equivalences:

scala> (f andThen g)(3) == g(f(3))
res0: Boolean = true

scala> (f compose g)(3) == f(g(3))
res1: Boolean = true

In the compose case the f and g are in the same order on both sides of the equation.

Unfortunately Scala's type inference often makes andThen (or >=>) more convenient, and it tends to be more widely used than compose. So this is a case where mathematical conventions and the quirks of Scala's type inference system are at odds. Scalaz (not too surprisingly, given the culture of the project) chooses the math side.

Travis Brown
  • 138,631
  • 12
  • 375
  • 680
  • Thanks, I see the point. I am wondering, how to implement smth. like that: suppose I have a function `child(name: String): XmlNode => Option[XmlNode]`. I would like to write `List("a", "b", "c").map(name => child(name)).foldMap(...)` to get a function that return a node by path `"a/b/c"`. And now I need to reverse the list :( which seems completely redundant.` – Michael Jul 14 '15 at 15:55
  • Yeah, that's a case where `>=>` does seem to correspond more closely to what the operation does. I'd probably skip the monoid and use `>=>` directly. – Travis Brown Jul 14 '15 at 20:05
  • Alternatively, it might be possible just to define such a monoid: `Monoid.instance(_ >=> _, {node => Some(node)})` (not sure how to do it right yet) and pass it to the `foldMap`. I will probably ask a new question about it. – Michael Jul 15 '15 at 04:13