Skip to content

Instantly share code, notes, and snippets.

@sam
Created September 29, 2015 20:43
Show Gist options
  • Save sam/7f3780e5267e0de7be7c to your computer and use it in GitHub Desktop.
Save sam/7f3780e5267e0de7be7c to your computer and use it in GitHub Desktop.
Is there a way to zip nested functions A => T and B => T into a (A, B) => T?
object helpers {
type Closeable = { def close() }
def using[T, S <: Closeable](source: S)(f: S => T) = {
val result = f(source) // Simplified for the example.
source.close()
result
}
}
// We can use this like:
import java.io.File
val out = new File("test")
using(new PrintWriter(out)) { _ println "Bob" }
// or:
using(Source.fromFile(out)) { _ println "Bob" }
// What if you want to nest the statements though?
using(new PrintWriter(out)) { out =>
using(new WebClient) { client =>
out print client.getPage(new URL("http://google.com")).asInstanceOf[HtmlPage].asXml()
}
}
// Ideally I could write the above something like this instead:
(using(new PrintWriter(out)) zip using(new WebClient)) { (out, client) =>
out print client.getPage(new URL("http://google.com")).asInstanceOf[HtmlPage].asXml()
}
@tpolecat
Copy link

This is one way to do it.

trait Using[A] { self =>

  def apply[B](f: A => B): B 

  def zip[B](other: Using[B]): Using[(A, B)] =
    new Using[(A, B)] {
      def apply[C](f: ((A, B)) => C): C =
        self.apply[C](a => other.apply[C](b => f(a, b)))
    }

}

...

def using[T, S <: Closeable](source: S): Using[S] = 
  new Using[S] {
    def apply[B](f: S => B) = 
      try f(source) finally source.close()
  }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment