(Logo design by Sandro Stucky - retrivied from the Martin Odersky's talk The Evolution of Scala, 2015).
This library implements the following data types:
data.Dequeue
data.Either
data.Heap
data.List
data.NonEmpty
data.Maybe
data.Queue
data.Ratio
data.Rational
data.Set
data.Stack
data.Tuple
and the following typeclasses:
Bounded
Enum
Eq
Fractional
Integral
Num
Ord
Real
RealFrac
Show
Semigroup
Monoid
The project has the following layout:
+ bench... JMH benchmarks
+ core.... core sources
+ docs.... tutorial
+ src
--+ main
----+ scala
------+ io
---------+ hascalator
------------+ Prelude.scala // the entry point
------------+ control // the "home" for Monad and Applicative
------------+ data // basic data types (ie Maybe, Either, List...)
------------+ dst // immutable, purely functional data structures
------------+ math // math types
------------+ typeclasses // typeclasses
Abstract Data Types have different implementation is Scala than they have in Haskell.
Where Haskell defines a type (Maybe
) and two constructor (Just
and Nothing
):
data Maybe a = Just a | Nothing
on the other hand, in Scala with the sealed trait pattern we basically have three different types
(Maybe
, Just
and None
).
sealed trait Maybe[+A]
private[data] final case class Just[A](value: A) extends Maybe[A]
private[data] case object None extends Maybe[Nothing]
To avoid to publish all the types, the only public type is the trait one, the more specific types are kept private. New values are created using smart constructors defined in the companion object for the trait.
object Maybe {
def just[A](x: A): Maybe[A]
def none[A]: Maybe[A]
}
with explicit return types, the type for the constructed value will always be the trait.
Haskell functions lose their semantics when translated in Scala (a strict language). Even in this context, where functions don't loose all their functionality during the translation they are kept in the API.
For instance, (++) :: [a] -> [a] -> [a]
(the function that appends two lists) allows
infinite lists. The data.List
implemented in Scala is not infinite and it's strictly
evaluated. Technically it's still possible to build an infinite list, but with the
strict evaluation the append operation will be rather useless (ie. the append
operation
will never terminate).
Other functions, iterate :: (a -> a) -> a -> [a]
, are not working in a strict
evaluated context and therefore were left out of the API.
Even if Haskell is much pure language than Scala, there are in the Prelude
example of non-total functions (ie head :: [a] -> a
). The corresponding methods
have the same semantics throwing an Exception
.
Where this is not a heavy burden, the API provides alternatives in the form of
PartialFunction
s or different return types that encode the possibility for missing
return values (Maybe
or Either
are returned in this case).
On this topic there are two main differences between Haskell and Scala. Scala is an hybrid language, mixing object oriented with functional programming. In former world, usually we have an instance of some object and we invoke methods against these instances instead of passing arguments to stand alone functions.
The classic example is the head
function for Lists:
head(myList)
vs myList.head
The object oriented style was favored, and almost all functions for the basic data
types (List
, Maybe
, Either
...) were translated to methods.
Scala has a local type inference and tries to infer the types from left to right, one argument list at the time. To help the compiler to infer the types, the order of arguments to methods have been changed from the Haskell corresponding functions.
It's possible to reproduce the non-strict semantic of Haskell in Scala, but it takes a lot of machinery. On the other hand, reproduce the purity approach followed by Haskell takes just discipline in the implementation.
This library is mostly strict in its evaluation, but the data structures are immutable, persistent and mostly pure. To improve performance impurity and mutability are used in the implementation, but this is hidden from the API clients.
Typeclasses were widely used, also in replacement for the common Java-esque
practices (hashcode
, equals
and toString
just to name few).
They are a first class element in the Haskell programming language, for Scala
the implementation is heavy on implicit values.
- Adriaan Moors, Frank Piessens, and Martin Odersky. Generics of a higher kind. In Proceedings of the 23rd ACM SIGPLAN conference on Object-oriented programming systems languages and applications (OOPSLA '08). ACM, New York, NY, USA, 423-438, 2008.
- Bruno CdS Oliveira, Adriaan Moors, and Martin Odersky. Type classes as objects and implicits. ACM Sigplan Notices. Vol. 45. No. 10. ACM, 2010.
- Danielle Ashley. Type lambdas and kind projector. Blog post retried from here, 2016.
- Gerth S. Brodal and Chris Okasaki. Optimal purely functional priority queues. J. Functional Programming, 6(6):839–857, 1996
- Haskell docs:
Prelude
. Retrived from here - Larry Liu Xinyu. Elementary Algorithms. Retrived from here, 2016.
- Louis Wasserman. Playing with Priority Queues. The Monad Reader, Issue 16 (pp. 37–52), 2010.
- Martin Odersky, Lex Spoon, and Bill Venners. 2016. Programming in Scala, Third Edition. Artima
- Martin Odersky and Matthias Zenger. Scalable component abstractions. In R. Johnson and R. P. Gabriel, editors, OOPSLA, pages 41–57. ACM, 2005.
- Nick Stanchenko. Unzipping Immutability. Scala By the Bay. Retrieved from here, 2016.
- Paul Chiusano, Rúnar Bjarnason. Functional Programming in Scala. Manning Publications, 2014.
- Ralf Hinze and Ross Paterson. Finger trees: a simple general-purpose data structure. J. Funct. Program. 16, 2 (March 2006), 197-217.
- Stephen Adams. Implementing Sets Efficiently in a Functional..
- Stephen Compall. Higher-kinded types: the difference between giving up, and moving forward. Blog post retried from here, 2016.
- Typelevel
Cats
: Lightweight, modular, and extensible library for functional programming. https://github.com/typelevel/cats - Typelevel
Dogs
: data structures for pure functional programming in scala. https://github.com/stew/dogs
Contributions via GitHub pull requests are gladly accepted from their original author. Along with any pull requests, please state that the contribution is your original work and that you license the work to the project under the project's open source license. Whether or not you state this explicitly, by submitting any copyrighted material via pull request, email, or other means you agree to license the material under the project's open source license and warrant that you have the legal authority to do so.
This code is open source software licensed under the Apache 2.0 License.