Skip to main content
Version: ZIO 2.x

ZIO Arrow

ZIO Arrow provides the ZArrow effect, which is a high-performance composition effect for the ZIO ecosystem.


ZArrow[E, A, B] is an effect representing a computation parametrized over the input (A), and the output (B) that may fail with an E. Arrows focus on composition and high-performance computation. They are like simple functions, but they are lifted into the ZArrow context.

ZArrow delivers three main capabilities:

  • High-PerformanceZArrow exploits JVM internals to dramatically decrease the number of allocations and dispatches, yielding an unprecedented runtime performance.

  • Abstract interfaceArrow is a more abstract data type, than ZIO Monad. It's more abstract than ZIO Streams. In a nutshell, ZArrow allows a function-like interface that can have both different inputs and different outputs.

  • Easy IntegrationZArrow can both input and output ZIO Monad and ZIO Stream, simplifying application development with different ZIO Effect types.


In order to use this library, we need to add the following line in our build.sbt file:

libraryDependencies += "io.github.neurodyne" %% "zio-arrow" % "0.2.1"


In this example we are going to write a repetitive task of reading a number from standard input and then power by 2 and then print the result:

import zio.arrow.ZArrow
import zio.arrow.ZArrow._
import zio.console._
import zio.{ExitCode, URIO}


object ArrowExample extends zio.App {

val isPositive : ZArrow[Nothing, Int, Boolean] = ZArrow((_: Int) > 0)
val toStr : ZArrow[Nothing, Any, String] = ZArrow((i: Any) => i.toString)
val toInt : ZArrow[Nothing, String, Int] = ZArrow((i: String) => i.toInt)
val getLine : ZArrow[IOException, Any, String] = ZArrow.liftM((_: Any) => getStrLn.provide(
val printStr : ZArrow[IOException, String, Unit] = ZArrow.liftM((line: String) => putStr(line).provide(
val printLine : ZArrow[IOException, String, Unit] = ZArrow.liftM((line: String) => putStrLn(line).provide(
val power2 : ZArrow[Nothing, Int, Double] = ZArrow((i: Int) => Math.pow(i, 2))
val enterNumber: ZArrow[Nothing, Unit, String] = ZArrow((_: Unit) => "Enter positive number (-1 to exit): ")
val goodbye : ZArrow[Nothing, Any, String] = ZArrow((_: Any) => "Goodbye!")

val app: ZArrow[IOException, Unit, Boolean] =
enterNumber >>> printStr >>> getLine >>> toInt >>>
power2 >>> toStr >>> printLine >>> ZArrow((_: Any) => true)
ZArrow((_: Any) => false)

val myApp = whileDo(app)(ZArrow(_ => ())) >>> goodbye >>> printLine

override def run(args: List[String]): URIO[zio.ZEnv, ExitCode] =

Let's see an example of running this program:

Enter positive number (-1 to exit): 25
Enter positive number (-1 to exit): 8
Enter positive number (-1 to exit): -1