Functional resource safety management

如果无法正常显示,请先停止浏览器的去广告插件。
分享至:
相关话题: #zalando
1. Functional resource safety management Functional resource safety management with the Bracket typeclass and Resource Javier Arrieta 23-07-2019
2. TABLE OF CONTENTS Zalando Javier The problem The bracket typeclass The Resource Monad Coding References 2
3. WE BRING FASHION TO PEOPLE IN 17 COUNTRIES 2008-2009 2010 2011 2012-2013 2018 3
4. 4
5. Who am I I am Javier, I work for Zalando as a software engineer. I have been developing software for 40 years now, doing Scala the last 7 years. @jarrieta https://www.linkedin.com/in/jarrieta/ We are hiring: https://grnh.se/4f5514971 5
6. The Problem How do we ensure we free up resources after usage? It usually involves a lot of boilerplate code 6
7. The Problem - Java way solution import java.io.{BufferedReader, File, FileReader} import scala.jdk.CollectionConverters._ import scala.util.control.NonFatal object alternatives { type FileParser = File => Either[Throwable, String] def javaWay(file: File): Either[Throwable, String] = { try { val reader = new FileReader(file) try { val buffered = new BufferedReader(reader) Right(buffered.lines().iterator().asScala.mkString("\n")) } finally { reader.close() } } catch { case NonFatal(e) => Left(e) } } } 7
8. The Problem - More Scala way solution import java.io.{BufferedReader, File, FileReader} import scala.jdk.CollectionConverters._ import scala.util.Try import scala.util.control.NonFatal object alternatives { type FileParser = File => Either[Throwable, String] val scalaWay: File => Either[Throwable, String] = { file => val tryText = for { reader <- Try(new FileReader(file)) buffered <- Try(new BufferedReader(reader)) text <- Try(buffered.lines().iterator().asScala.mkString("\n")) } yield text tryText.toEither } } 8
9. The Problem - Using Source import java.io.FileInputStream import scala.io.Source import scala.util.Try object alternatives { type FileParser = File => Either[Throwable, String] val withSource: File => Either[Throwable, String] = {file => Try(Source.fromInputStream(new FileInputStream(file)).getLines().mkString("\n")).toEither } } Only works for Input Streams ¯\_(ツ)_/¯ 9
10. The Functional Solution - Bracket Typeclass /** * An extension of `MonadError` exposing the `bracket` operation, * a generalized abstracted pattern of safe resource acquisition and * release in the face of errors or interruption. * * @define acquireParam is an action that "acquires" some expensive * resource, that needs to be used and then discarded * * @define useParam is the action that uses the newly allocated * resource and that will provide the final result */ trait Bracket[F[_], E] extends MonadError[F, E] { /** * A generalized version of [[bracket]] which uses [[ExitCase]] * to distinguish between different exit cases when releasing * the acquired resource. * * @param acquire $acquireParam * @param use $useParam * @param release is the action that's supposed to release the * allocated resource after `use` is done, by observing * and acting on its exit condition. Throwing inside * this function leads to undefined behavior since it's * left to the implementation. */ def bracketCase[A, B](acquire: F[A])(use: A => F[B]) (release: (A, ExitCase[E]) => F[Unit]): F[B] 10
11. The Functional Solution - Bracket Typeclass - continued /** * Operation meant for specifying tasks with safe resource * acquisition and release in the face of errors and interruption. * * This operation provides the equivalent of `try/catch/finally` * statements in mainstream imperative languages for resource * acquisition and release. * * @param acquire $acquireParam * @param use $useParam * @param release is the action that's supposed to release the * allocated resource after `use` is done, regardless of * its exit condition. Throwing inside this function * is undefined behavior since it's left to the implementation. */ def bracket[A, B](acquire: F[A])(use: A => F[B]) (release: A => F[Unit]): F[B] = bracketCase(acquire)(use)((a, _) => release(a)) } 11
12. The Functional Solution - Usage - The Resource class /** * @tparam F the effect type in which the resource is allocated and released * @tparam A the type of resource */ sealed abstract class Resource[F[_], A] { import Resource.{Allocate, Bind, Suspend} /** * Allocates a resource and supplies it to the given function. The * resource is released as soon as the resulting `F[B]` is * completed, whether normally or as a raised error. * * @param f the function to apply to the allocated resource * @return the result of applying [F] to */ def use[B](f: A => F[B])(implicit F: Bracket[F, Throwable]): F[B] = ??? def flatMap[B](f: A => Resource[F, B]): Resource[F, B] = ??? def map[B](f: A => B)(implicit F: Applicative[F]): Resource[F, B] = } 12
13. The Functional Solution - The example solution import java.io.{BufferedReader, File, FileReader} object alternatives { type FileParser = File => Either[Throwable, String] val resourceFileParser: FileParser.FileParser = { file => val ioText = for { reader <- Resource.fromAutoCloseable(IO(new FileReader(file))) buffered <- Resource.fromAutoCloseable(IO(new BufferedReader(reader))) text <- Resource.liftF(IO(buffered.lines().iterator().asScala.mkString("\n"))) } yield text ioText.use(IO.pure).attempt.unsafeRunSync() } } 13
14. Live coding demo 14
15. References Self https://docs.google.com/presentation/d/1DEy_2j9dMoEbwiStHDKd4XUd4GxErlHP0LlDdDSoX64 Example https://github.com/javierarrieta/bracket-scala-meetup Cats-effect https://typelevel.org/cats-effect Http4s https://http4s.org/v0.20/ ZIO https://zio.dev/ 15

首页 - Wiki
Copyright © 2011-2025 iteam. Current version is 2.142.1. UTC+08:00, 2025-04-03 04:49
浙ICP备14020137号-1 $访客地图$