Arrow[Function1]

On August 2, 2011, in Scala, scalaz, by OleTraveler

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)
 

Leave a Reply

Your email address will not be published. Required fields are marked *