Scalaz defines Arrow as such.
trait Arrow[A[_, _]] { val category: Category[A] def arrow[B, C](f: B => C): A[B, C] def first[B, C, D](a: A[B, C]): A[(B, D), (C, D)] def second[B, C, D](a: A[B, C]): A[(D, B), (D, C)] }
Easy to see with Function1 implementation.
implicit def Function1Arrow: Arrow[Function1] = new Arrow[Function1] { val category = Category.Function1Category def arrow[B, C](f: B => C) = f /** takes a Function1[B,C] and returns a Function1[(B,D),(C,D)]. As you can see * only the _1, or the 'first' argument is modified to a different type * and the _2 or 'second' is not touched. */ def first[B, C, D](a: B => C) = (bd: (B, D)) => (a(bd._1), bd._2) /** takes a Function1[B,C] and returns a Function1[(D,B),(D,C)]. * Only the _2 or second element of the Tuple is touched. */ def second[B, C, D](a: B => C) = (db: (D, B)) => (db._1, a(db._2)) }
And here we have some example uses.
scala> val plus: Function1[Int,Int] = (_:Int) + 1 plus: (Int) => Int = <function1> scala> val firstChar: Function1[String,Option[Char]] = (s:String) => Option(s.charAt(0)) firstChar: (String) => Option[Char] = <function1> scala> val m2 = Map(1 -> "astroman", 2 -> "boat") m2: scala.collection.immutable.Map[Int,java.lang.String] = Map((1,astroman), (2,boat)) scala> m2.map(plus.first) res37: scala.collection.immutable.Map[Int,java.lang.String] = Map((2,astroman), (3,boat)) scala> m2.map(firstChar.second) res39: scala.collection.immutable.Map[Int,Option[Char]] = Map((1,Some(a)), (2,Some(b)))
The trait MAB defines some useful functions for composing functions.
The *** will create a function in which each composted function will work on individual values of the Tupl2.
scala> val p = plus *** firstChar p: ((Int, String)) => (Int, Option[Char]) = <function> scala> m2.map(p) res41: scala.collection.immutable.Map[Int,Option[Char]] = Map((2,Some(a)), (3,Some(b)))
&&& will perform two operations on a single value and put the values in a Tuple2.
scala> val plus2 = (_:Int) + 2 plus2: (Int) => Int = <function1> scala> val q = plus &&& plus2 q: (Int) => (Int, Int) = <function1> scala> q(3) res44: (Int, Int) = (4,5)
The product method will perform the same operation on both elements of the Tuple2
scala> plus.product apply (1 -> 2) res46: (Int, Int) = (2,3)