Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up

Principled Functional Programming in Scala

License

NotificationsYou must be signed in to change notification settings

scalaz/scalaz

Repository files navigation

Scalaz is a Scala library for functional programming.

It provides purely functional data structures to complement those from the Scala standard library.It defines a set of foundational type classes (e.g.Functor,Monad) and corresponding instances fora large number of data structures.

IRC

Getting Scalaz

The current stable version is 7.3.8, which is cross-built against Scala 2.12.x, 2.13.x, 3.x and Scala.js, scala-native.

If you're using SBT, add the following line to your build file:

libraryDependencies+="org.scalaz"%%"scalaz-core"%"7.3.8"

For Maven and other build tools, you can visitsearch.maven.org.(This search will also list all available modules of scalaz.)

To get sample configurations, click on the version of the module you are interested in.You can also find direct download links at the bottom of that page. Choose the file ending in7.3.8.jar.

Quick Start

importscalaz._importstd.option._,std.list._// functions and type class instances for Option and Listscala>Apply[Option].apply2(some(1), some(2))((a, b)=> a+ b)res0:Option[Int]=Some(3)scala>Traverse[List].traverse(List(1,2,3))(i=> some(i))res1:Option[List[Int]]=Some(List(1,2,3))

Use of theOps classes, defined underscalaz.syntax.

importscalaz._importstd.list._// type class instances for Listimportsyntax.bind._// syntax for the Bind type class (and its parents)scala>List(List(1)).joinres0:List[Int]=List(1)scala>List(true,false).ifM(List(0,1),List(2,3))res1:List[Int]=List(0,1,2,3)

We've gone to great lengths to give you ana-la-carte importing experience, but if you prefer an all-you-can-eatbuffet, you're in luck:

importscalaz._importScalaz._scala>NonEmptyList(1,2,3).cojoinres0: scalaz.NonEmptyList[scalaz.NonEmptyList[Int]]=NonEmptyList(NonEmptyList(1,2,3),NonEmptyList(2,3),NonEmptyList(3))scala>1.node(2.leaf,3.node(4.leaf))res1: scalaz.Tree[Int]= <tree>scala>List(some(1), none).sumlres2:Option[Int]=Some(1)

Resources

Let the types speak for themselves via theScalaz Scaladocs!

Theexamples module contains some snippets of Scalaz usage.

Thewiki contains release and migration information.

Talk with us by joiningIRC: irc.libera.chat channel #scalaz, or jointhe Scalaz mailing list on Google Groups.

Thetypelevel blog has some great posts such asTowards Scalaz byAdelbert Chang.

Learning Scalaz is a great series of blog posts byEugene Yokota. Thanks, Eugene!

Changes in Version 7

Scalaz 7 represents a major reorganization of the library. We have taken a fresh lookat the challenges of encoding type classes in Scala, in particular at when and how toemploy the implicit scope.

At a glance

  • scalaz.{effect, iteratee} split to separate sub-projects;scalaz.{http, geo} dropped.
  • Refined and expanded the type class hierarchy.
  • Type class instances are no longer defined in the companion objects of the type class.Instances for standard library types are defined underscalaz.std, and instances forScalaz data types are defined in the companion object for those types. An instance definitioncan provide multiple type classes in a single place, which was not always possible in Scalaz 6.
  • Type class instances have been organized to avoid ambiguity, a problem that arises wheninstances are dependent on other instances (for example,Monoid[(A, B)])
  • Use of implicit views to provide access to Scalaz functionality as extension methodshas been segregated toscalaz.syntax, and can be imported selectively, and need notbe used at all.
  • Related functions are defined in the type class trait, to support standaloneusage of the type class. In Scalaz 6, these were defined inIdentity,MA, orMAB.
  • New data structures have been added, and existing ones generalized. A number of monadtransformers have been provided, in some cases generalizing old data structures.

Modularity

Scalaz has been modularised.

  • scalaz-core: Type class hierarchy, data structures, type class instances for the Scala and Java standard libraries,implicit conversions / syntax to access these.
  • scalaz-effect: Data structures to represent and compose IO effects in the type system.
  • scalaz-iteratee: Experimental new Iteratee implementation

Type Class Hierarchy

  • Type classes form an inheritance hierarchy, as in Scalaz 6. This is convenient both at the call site and at thetype class instance definition. At the call site, it ensures that you can call a method requiring a more generaltype class with an instance of a more specific type class:
defbar[M[_]:Functor]= ()deffoo[M[_]:Monad]= bar[M]// Monad[M] is a subtype of Functor[M]
  • The hierarchy itself is largely the same as in Scalaz 6. However, there have been a fewadjustments, some method signatures have been adjusted to support better standalone usage, so code depending on these willneed to be re-worked.

Type Class Instance Definition

  • Constructive implicits, which create a type class instance automatically based on instances ofall parent type classes, are removed. These led to subtle errors with ambiguous implicits, such asthis problem withFunctorBindApply
  • Type class instances are no longer declared in fragments in the companion objects of the type class. Instead, theyare defined in the packagescalaz.std, and must be imported. These instances are defined in traits which will bemixed together into an object for importingen-masse, if desired.
  • A single implicit can define a number of type class instances for a type.
  • A type class definition can override methods (including derived methods) for efficiency.

Here is an instance definition forOption. Notice that the methodmap has been overridden.

implicitvaloption:Traverse[Option]withMonadPlus[Option]=newTraverse[Option]withMonadPlus[Option] {defpoint[A](a:=>A)=Some(a)defbind[A,B](fa:Option[A])(f:A=>Option[B]):Option[B]= fa flatMap foverridedefmap[A,B](fa:Option[A])(f:A=>B):Option[B]= fa map fdeftraverseImpl[F[_],A,B](fa:Option[A])(f:A=>F[B])(implicitF:Applicative[F])=      fa map (a=>F.map(f(a))(Some(_):Option[B])) getOrElseF.point(None)defempty[A]:Option[A]=Nonedefplus[A](a:Option[A],b:=>Option[A])= a orElse bdeffoldR[A,B](fa:Option[A],z:B)(f: (A)=> (=>B)=>B):B= famatch {caseSome(a)=> f(a)(z)caseNone=> z    }  }

To use this, one would:

importscalaz.std.option.optionInstance// or, importing all instances en-masse// import scalaz.Scalaz._valM=Monad[Option]valoi:Option[Int]=M.point(0)

Syntax

We co-opt the termsyntax to refer to the way we allow the functionality of Scalaz to becalled in theobject.method(args) form, which can be easier to read, and, given that type inferencein Scala flows from left-to-right, can require fewer type annotations.

  • No moreIdentity,MA, orMAB from Scalaz 6.
  • Syntax is segregated from rest of the library, in a sub-packagescalaz.syntax.
  • All Scalaz functionality is availablewithout using the provided syntax, by directly calling methodson the type class or its companion object.
  • Syntax is availablea-la-carte. You can import the syntax for working with particulartype classes where you need it. This avoids flooding the autocompletion in your IDE withevery possible extension method. This should also help compiler performance,by reducing the implicit search space.
  • Syntax is layered in the same way as type classes. Importing the syntax for, say,Applicativewill also provide the syntax forApply andFunctor.

Syntax can be imported in two ways. Firstly, the syntax specialized for a particular instanceof a type class can be imported directly from the instance itself.

// import the type class instanceimportscalaz.std.option.optionInstance// import the implicit conversions to `MonadOps[Option, A]`, `BindOps[Option, A]`, ...importoptionInstance.monadSyntax._valoi:Option[Option[Int]]=Some(Some(1))// Expands to: `ToBindOps(io).join`oi.join

Alternatively, the syntax can be imported for a particular type class.

// import the type class instanceimportscalaz.std.option.optionInstance// import the implicit conversions to `MonadOps[F, A]`, `BindOps[F, A]`, ...importscalaz.syntax.monad._valoi:Option[Option[Int]]=Some(Some(1))// Expands to: ToBindOps(io).joinoi.join

For some degree of backwards compatibility with Scalaz 6, the über-import ofimport scalaz.Scalaz._will importall implicit conversions that provide syntax (as well as type class instances and otherfunctions). However, we recommend to review usage of this and replace with more focussed imports.

Standalone Type Class Usage

Type classes should be directly usable, without first needing to trigger implicit conversions. This might bedesirable to reduce the runtime or cognitive overhead of the pimped types, or to define your own pimpedtypes with a syntax of your choosing.

  • The methods in type classes have been curried to maximize type inference.
  • Derived methods, based on the abstract methods in a type class, are defined in the type class itself.
  • Each type class companion object is fitted with a convenientapply method to obtain an instance of the type class.
// Equivalent to `implicitly[Monad[Option]]`valO=Monad[Option]// `bind` is defined with two parameter sections, so that the type of `x` is inferred as `Int`.O.bind(Some(1))(x=>Some(x*2))defplus(a:Int,b:Int)= a+ b// `Apply#lift2` is a function derived from `Apply#ap`.valplusOpt=O.lift2(plus)

Type Class Instance Dependencies

Type class instances may depend on other instances. In simple cases, this is as straightforward as adding an implicitparameter (or, equivalently, a context bound), to the implicit method.

implicitdefoptionMonoid[A:Semigroup]:Monoid[Option[A]]=newMonoid[Option[A]] {defappend(f1:Option[A],f2:=>Option[A]):Option[A]= (f1, f2)match {case (Some(a1),Some(a2))=>Some(Semigroup[A].append(a1, a2))case (Some(a1),None)=> f1case (None,Some(a2))=> f2case (None,None)=>None    }defzero:Option[A]=None  }

Type class instances for 'transformers', such asOptionT, present a more subtle challenge.OptionT[F, A]is a wrapper for a value of typeF[Option[A]]. It allows us to write:

valot=OptionT(List(Some(1),None))ot.map((a:Int)=> a*2)// OptionT(List(Some(2), None))

The methodOptionT#map requires an implicit parameter of typeFunctor[F], whereasOptionT#flatMaprequires one of typeMonad[F]. The capabilities ofOptionT increase with those ofF. We need to encodethis into the type class instances for[a]OptionT[F[A]].

This is done with a hierarchy oftype class implementation traitsand a corresponding set ofprioritized implicit methods.

In case of ambiguous implicits, Scala will favour one defined in a sub-class of the other. This is to avoid ambiguitywhen in cases like the following:

typeOptionTList[A]=OptionT[List[A]]implicitly[Functor[OptionTList]]// Candidates:// 1. OptionT.OptionTFunctor[List](implicitly[Functor[List]])// 2. OptionT.OptionTMonad[List](implicitly[Functor[List]])// #2 is defined in a subclass of the enclosing class of #1, so #2 is preferred.

Transformers and Identity

A stronger emphasis has been placed on transformer data structures (aka Monad Transformers). For exampleState is nowa type alias forStateT[Id, A, B].

Id is defined in thescalaz package object as:

typeId[A]=A

Contributing

Documentation for contributors

Credits

Support for Scalaz development is provided byJetbrains.

Thanks to Mark Harrah and the sbt contributors for providingour build tool.


[8]ページ先頭

©2009-2025 Movatter.jp