9

I was trying to convert a haskell example, I came across earlier, to scalaz. The original example was this:

("Answer to the ", (*)) <*> ("Ultimate Question of ", 6) <*> ("Life, the Universe, and Everything", 7)

Which, as far as I am able to understand, uses this instance.

It does not get converted to scalaz literally:

scala> ("Answer to the ", ((_: Int) * (_: Int)) curried) |@| ("Ultimate Question of ", 6) |@| ("Life, the Universe, and Everything", 7) tupled
res37: (java.lang.String, (Int => (Int => Int), Int, Int)) = (Answer to the Ultimate Question of Life, the Universe, and Everything,(<function1>,6,7))

Although, I've looked for an instance, and it seems to be there (again, as far as I am able to understand).

So, the question is: why does not it work like this? Or what did I miss/did not get correctly?

tofcoder
  • 2,352
  • 1
  • 20
  • 28
George
  • 8,368
  • 12
  • 65
  • 106
  • 1
    This code does indeed dispatch to the applicative instance for tuples. Which in turn uses the monoid `mappend` for lists (concatentation). So it is function composition of the 2nd component of the tuple, with list concatentation of the first part. – Don Stewart Jun 07 '12 at 19:37

1 Answers1

5

Scalaz's equivalent of Control.Applicative's <*> is also called <*>, although it confusingly takes its arguments in the opposite order. So the following works:

val times = ((_: Int) * (_: Int)) curried
val a = "Answer to the "
val b = "Ultimate Question of "
val c = "Life, the Universe, and Everything"

(c, 7) <*> ((b, 6) <*> (a, times))

Or, as I've noted in response to your comment, you could use the following if you want to stick with |@|:

(a -> times |@| b -> 6 |@| c -> 7)(_ apply _ apply _)

I personally prefer the <*> version, even if it feels backwards.


We can walk through what's going on in a little more detail. First of all, you don't need the full power of Applicative here—Apply will do. We can get the Apply instance for tuples using implicitly:

scala> val ai = implicitly[Apply[({type λ[α]=(String, α)})#λ]]
ai: scalaz.Apply[[α](java.lang.String, α)] = scalaz.Applys$$anon$2@3863f03a

Now we can apply our first tuple to the second:

scala> :t ai(a -> times, b -> 6)
(java.lang.String, Int => Int)

And the result to the third:

scala> :t ai(ai(a -> times, b -> 6), c -> 7)
(java.lang.String, Int)

Which is what we want:

scala> ai(ai(a -> times, b -> 6), c -> 7)._1
res0: java.lang.String = Answer to the Ultimate Question of Life, the Universe, and Everything

scala> ai(ai(a -> times, b -> 6), c -> 7)._2
res1: Int = 42

The <*> method on MA just wraps this up a little more nicely.

Travis Brown
  • 138,631
  • 12
  • 375
  • 680
  • Thanks, works like it is supposed to. By the way, do you have any idea, how to do this with the ApplicativeBuilder and if it will look any better that way? – George Jun 07 '12 at 19:49
  • 1
    Sure, you could do something like `(a -> times |@| b -> 6 |@| c -> 7)(_ apply _ apply _)`, but I think the `<*>` version is nicer. – Travis Brown Jun 07 '12 at 20:08
  • Yep, this works. I was mislead by the fact, that `tupled` glued up the monoid, so I thought, it would apply the function too. – George Jun 08 '12 at 06:38