Related
I'm quite new to functional programming. However, I read about the Free Monad, and I'm trying to use it in a toy project. In this project, I model the stock's portfolio domain. As suggested in many books, I defined an algebra for the PortfolioService and an algebra for the PortfolioRepository.
I want to use the Free monad in the definition of the PortfolioRepository algebra and interpreter. For now, I did not define the PortfolioService algebra in terms of the Free monad.
However, if I do so, in the PortfolioService interpreter, I cannot use the algebra of the PortfolioRepository because of different used monads. For example, I cannot use the monads Either[List[String], Portfolio], and Free[PortfolioRepoF, Portfolio] inside the same for-comprehension :(
I doubt that if I start to use the Free monad to model an algebra, all the other algebra that need to compose with it must be defined in terms of the Free monad.
Is it true?
I am using Scala and Cats 2.2.0.
99% of the time Free monad is interchangeable with Tagless final:
you can pass Free[S, *] as your Monad instance
you can .foldMap Free[S, A] using S ~> F mapping with Monad[F] into F[A]
The only difference is when do you interpret:
tagless interprets immediately, so it require you to pass around type class instances for your F, but since F is a type parameter it gives the impression that it is deferred - because it defers the moment when the type is chosen
free monad lets you create the value immediately with no dependencies on type classes, you can store them as vals in objects, there are no dependencies on type classes. The price you pay is intermediate representation that you ultimately want to discard as soon as you will be able to interpret into useful result. On the other hand it is missing tagless' ability to constrain your operation only to certain algebras (e.g. only Functor, only Applicative, etc to better control effects in dependencies).
Nowadays things moved in favor of tagless final. Free monad is used internally in IO monad implementation (Cats Effect IO, Monix Task, ZIO) and in e.g. Doobie (though from what I heard Doobie's author was thinking about rewriting it into tagless, or at least regretting not using tagless?).
If you want to learn how to use that in modelling there is a book by Gabriel Volpe - Practical FP in Scala that uses tagless final as well as my own small project that uses Cats, FS2, Tapir, tagless etc which can demonstrate some ideas.
If you intend to use Free, then well, there are some challenges:
sealed trait DomainA[A] extends Product with Serializable
object DomainA {
case class Service1(input1: X, input2: Y) extends DomainA[Z]
// ...
def service1(input1: X, input2: Y): Free[DomainA, Z] =
Free.liftF(Service1(input1, input2))
}
val interpreterA: DomainA ~> IO = ...
You use Free[DomainA, *], combine it using .map, .flatMap, etc, interpret it with interpretA.
Then you add another domain, DomainB. And the fun begins:
you cannot just combine Free[DomainA, *] with Free[DomainB, *] because they are different types, you need to align them to make that possible!
so, you have to combine all algebras into one:
type BusinessLogic[A] = EitherK[DomainA, DomainB, A]
implicit val injA: InjectK[DomainA, BusinessLogic] = ...
implicit val injB: InjectK[DomainB, BusinessLogic] = ...
your services cannot hardcode one algebra, you have to inject current algebra into a "bigger" one:
def service1[Total[_]](input1: X, input2: Y)(
implicit inject: InjectK[DomainA, Total]
): Free[Total, Z] =
Free.liftF(inject.inj(Service1(input1, input2)))
your interpreter is also more complex now:
val interpreterTotal: EitherK[DomainA, DomainB, *] ~> IO =
new (EitherK[DomainA, DomainB, *] ~> IO) {
def apply[A](fa: EitherK[DomainA, DomainB, A]) =
fa.run.fold(interpreterA, interpreterB)
}
and it gets more complex with each new added algebra (EitherK[DomainA, EitherK[DomainB, ..., *], *]).
In tagless final there is always a dependency but almost always on one type - F - and empirical evidences of many people shows that is easier to use despite being theoretically equal in power to a free monad. But it is not a scientific argument, so feel free to experiment with free monad on your own. See e.g. this Underscore article about using multiple DSLs at once.
Whether you pick one or the other you are NOT forced to use it everywhere - everything that is Free can be (should be) interpreted into a specific implementation, tagless makes you pass the specific implementation as argument so you can use either for a single component, that is interpreted on its edge.
I'm studying functional programming in Scala and I learnt term monad. In short monad is:
trait M[A] {
def flatMap[B](f: A => M[B]): M[B]
}
def unit[A](x: A): M[A]
I know monad is just a concept based on above 2 rules. And we can meet many monads in real world such as List, Future ....
The only one problem I don't know is: why should we know term "monad" as comparing to understanding List apis, Future apis or anything apis ... Is understanding monad help us write better code or can design better functional code structure.
Thanks
Because Monad already is a known term in category theory. There are also 3 very important Monad laws, that a Monad has to adhere to.
In theory, we could call Monads whatever we'd like, i.e. "FlatMappable" or "Bindable", but the name "Monad" is already an established term in the functional programming community and is deeply linked to the Monad laws.
As to why you should learn to appreciate Monads over learning each api individually, it's all about abstraction and reuse of knowledge. Oftentimes when we look at a new concept we compare them to concepts we already know.
If you already understand the Future Monad, understanding the Task Monad will be much easier.
It's also good to mention, that for-comprehensions in Scala work exclusively on Monads. In fact for-comprehensions are just syntactic sugar for flatMap and map (there's also filter, but that's not incredibly relevant to Monads). So recognizing if something is a Monad instance, enables you to utilize this extra piece of syntactic sugar.
Also once you fully grasp the abstraction you can make use of concepts like Monad transformers, where the actual type of the Monad is less important.
Lastly, here are the Monad laws for completeness sake:
Left identity: M[F].pure(x).flatMap(f) == f(x)
Right identity: m.flatMap(pure(_)) == m
Associativity: m.flatMap(f).flatMap(g) == m.flatMap(x => f(x).flatMap(g))
About Monad API vs concrete APIs:
An example could be Free Monad pattern. It essentialy uses (at least) two monads: first one is wrapping your DSL's expressions, and the second one is effect monad, that is, modality that you interpret your expressions in (Option corresponds to something that could fail, Future also adds latency etc).
To be more concrete: consider a task where you have some latency, and you decide to use Futures. How will you unit test that? Return some futures and then use Await? Apart from adding unnecessary complexity, you can run into some problems with that. And you won't actually need to use Futures for some tests. The answer is to parametrize methods that are supposed to use Futures with Monad, so you can just use Identity monad, or Option, and just forget about aforementioned problem.
I'd like to create a simple wrapper for computations. The built-in scala monads (TraversableLike) seems sufficient for me. And they have already syntax sugar. From some point of view scala collection traits are accidental monads. And there intended monads provided by the scalaz library.
What uses cases benefit from complex type classed monads of scalaz? What functionality is unfeasible for built-in monads and indicate need for scalaz?
Some clarification.
This question is not a holy war inheritance vs type classes. My question is about infrastructure that provides scalaz. Not any library with type classes approach, but this mentioned library. It slightly complicates things. But also it have bunch of utility classes that have no matches in scala collection library. Because it is a collection library, not a monadic. So the question is about the additional functionality provided by scalaz. In which cases does it matter?
First for a point about terminology: it's sometimes useful shorthand to say things like "Option is a monad", but "Option has a monad instance" or "Option is monadic" is clearer. It's potentially a little confusing to say that Scalaz provides a bunch of monads—what it provides is a Monad type class and instances of that type class for a number of types, including some of its own (e.g. \/, Task, etc.) and some from the standard library (List, Option, etc.).
So I'm going to answer a question which is similar to your question: what's the value of an explicit Monad type class over the monadic syntactic sugar provided by the standard library?
One place where having an explicit Monad representation is useful is when you want to define your own generic combinators or operations. Suppose I want to write a method addM that takes two monadic M[Int] values and adds them in the monad. It's easy to write for Option:
def addM(oa: Option[Int], ob: Option[Int]): Option[Int] = for {
a <- oa
b <- ob
} yield a + b
Or for lists:
def addM(oa: List[Int], ob: List[Int]): List[Int] = for {
a <- oa
b <- ob
} yield a + b
These two implementations obviously have a lot in common, and it'd be nice to be able to write a single generic implementation that would work in both cases—and for any other monadic type as well. This is really hard if we only have the standard library's hand-wavy monadic syntax, and really easy if we have a Monad type class.
I know what the monads are and how to use them. What I don't understand is what makes, let's say, Option a monad?
In Haskell a monad Maybe is a monad because it's instantiated from Monad class (which has at least 2 necessary functions return and bind that makes class Monad, indeed, a monad).
But in Scala we've got this:
sealed abstract class Option[+A] extends Product with Serializable { ... }
trait Product extends Any with Equals { ... }
Nothing related to a monad.
If I create my own class in Scala, will it be a monad by default? Why not?
Monad is a concept, an abstract interface if you will, that simply defines a way of composing data.
Option supports composition via flatMap, and that's pretty much everything that is needed to wear the "monad badge".
From a theoretical point of view, it should also:
support a unit operation (return, in Haskell terms) to create a monad out of a bare value, which in case of Option is the Some constructor
respect the monadic laws
but this is not strictly enforced by Scala.
Monads in scala are a much looser concept that in Haskell, and the approach is more practical.
The only thing monads are relevant for, from a language perspective, is the ability of being used in a for-comprehension.
flatMap is a basic requirement, and you can optionally provide map, withFilter and foreach.
However, there's no such thing as strict conformance to a Monad typeclass, like in Haskell.
Here's an example: let's define our own monad.
class MyMonad[A](value: A) {
def map[B](f: A => B) = new MyMonad(f(value))
def flatMap[B](f: A => MyMonad[B]) = f(value)
override def toString = value.toString
}
As you see, we're only implementing map and flatMap (well, and toString as a commodity).
Congratulations, we have a monad! Let's try it out:
scala> for {
a <- new MyMonad(2)
b <- new MyMonad(3)
} yield a + b
// res1: MyMonad[Int] = 5
Nice! We are not doing any filtering, so we don't need to implement withFilter. Also since we're yielding a value, we don't need foreach either. Basically you implement whatever you wish to support, without strict requirements. If you try to filter in a for-comprehension and you haven't implemented withFilter, you'll simply get a compile-time error.
Anything that (partially) implements, through duck-typing, the FilterMonadic trait is considered to be a monad in Scala. This is different than how monads are represented in Haskell, or the Monad typeclass in scalaz. However, in order to benefit of the for comprehension syntactic sugar in Scala, an object has to expose some of the methods defined in the FilterMonadic trait.
Also, in Scala, the equivalent of the Haskell return function is the yield keyword used for producing values out of a for comprehension. The desugaring of yield is a call to the map method of the "monad".
The way I'd put it is that there's an emerging distinction between monads as a design pattern vs. a first-class abstraction. Haskell has the latter, in the form of the Monad type class. But if you have a type that has (or can implement) the monadic operations and obeys the laws, that's a monad as well.
These days you can see monads as a design pattern in Java 8's libraries. The Optional and Stream types in Java 8 come with a static of method that corresponds to Haskell return, and a flatMap method. There is however no Monad type.
Somewhere in between you also have the "duck-typed" approach, as Ionuț G. Stan's answer calls out. C# has this as well—LINQ syntax isn't tied to a specific type, but rather it can be used with any class that implements certain methods.
Scala, per se, does not provide the notion of a monad. You can express a monad as a typeclass but Scala also doesn't provide the notion of a typeclass. But Cats does. So you can create a Monad in Scala with the necessary boiler plate, e.g. traits and implicits cleverly used, or you can use cats which provides a monad trait out of the box. As a comparison, Haskel provides monads as part of the language. Regarding your specific question, an Option can be represented as a monad because it has a flatMap method and a unit method (wrapping a value in a Some or a Future, for example).
I am a Scala programmer, learning Haskell now. It's easy to find practical use cases and real world examples for OO concepts, such as decorators, strategy pattern etc. Books and interwebs are filled with it.
I came to the realization that this somehow is not the case for functional concepts. Case in point: applicatives.
I am struggling to find practical use cases for applicatives. Almost all of the tutorials and books I have come across so far provide the examples of [] and Maybe. I expected applicatives to be more applicable than that, seeing all the attention they get in the FP community.
I think I understand the conceptual basis for applicatives (maybe I am wrong), and I have waited long for my moment of enlightenment. But it doesn't seem to be happening. Never while programming, have I had a moment when I would shout with a joy, "Eureka! I can use applicative here!" (except again, for [] and Maybe).
Can someone please guide me how applicatives can be used in a day-to-day programming? How do I start spotting the pattern? Thanks!
Applicatives are great when you've got a plain old function of several variables, and you have the arguments but they're wrapped up in some kind of context. For instance, you have the plain old concatenate function (++) but you want to apply it to 2 strings which were acquired through I/O. Then the fact that IO is an applicative functor comes to the rescue:
Prelude Control.Applicative> (++) <$> getLine <*> getLine
hi
there
"hithere"
Even though you explicitly asked for non-Maybe examples, it seems like a great use case to me, so I'll give an example. You have a regular function of several variables, but you don't know if you have all the values you need (some of them may have failed to compute, yielding Nothing). So essentially because you have "partial values", you want to turn your function into a partial function, which is undefined if any of its inputs is undefined. Then
Prelude Control.Applicative> (+) <$> Just 3 <*> Just 5
Just 8
but
Prelude Control.Applicative> (+) <$> Just 3 <*> Nothing
Nothing
which is exactly what you want.
The basic idea is that you're "lifting" a regular function into a context where it can be applied to as many arguments as you like. The extra power of Applicative over just a basic Functor is that it can lift functions of arbitrary arity, whereas fmap can only lift a unary function.
Since many applicatives are also monads, I feel there's really two sides to this question.
Why would I want to use the applicative interface instead of the monadic one when both are available?
This is mostly a matter of style. Although monads have the syntactic sugar of do-notation, using applicative style frequently leads to more compact code.
In this example, we have a type Foo and we want to construct random values of this type. Using the monad instance for IO, we might write
data Foo = Foo Int Double
randomFoo = do
x <- randomIO
y <- randomIO
return $ Foo x y
The applicative variant is quite a bit shorter.
randomFoo = Foo <$> randomIO <*> randomIO
Of course, we could use liftM2 to get similar brevity, however the applicative style is neater than having to rely on arity-specific lifting functions.
In practice, I mostly find myself using applicatives much in the same way like I use point-free style: To avoid naming intermediate values when an operation is more clearly expressed as a composition of other operations.
Why would I want to use an applicative that is not a monad?
Since applicatives are more restricted than monads, this means that you can extract more useful static information about them.
An example of this is applicative parsers. Whereas monadic parsers support sequential composition using (>>=) :: Monad m => m a -> (a -> m b) -> m b, applicative parsers only use (<*>) :: Applicative f => f (a -> b) -> f a -> f b. The types make the difference obvious: In monadic parsers the grammar can change depending on the input, whereas in an applicative parser the grammar is fixed.
By limiting the interface in this way, we can for example determine whether a parser will accept the empty string without running it. We can also determine the first and follow sets, which can be used for optimization, or, as I've been playing with recently, constructing parsers that support better error recovery.
I think of Functor, Applicative and Monad as design patterns.
Imagine you want to write a Future[T] class. That is, a class that holds values that are to be calculated.
In a Java mindset, you might create it like
trait Future[T] {
def get: T
}
Where 'get' blocks until the value is available.
You might realize this, and rewrite it to take a callback:
trait Future[T] {
def foreach(f: T => Unit): Unit
}
But then what happens if there are two uses for the future? It means you need to keep a list of callbacks. Also, what happens if a method receives a Future[Int] and needs to return a calculation based on the Int inside? Or what do you do if you have two futures and you need to calculate something based on the values they will provide?
But if you know of FP concepts, you know that instead of working directly on T, you can manipulate the Future instance.
trait Future[T] {
def map[U](f: T => U): Future[U]
}
Now your application changes so that each time you need to work on the contained value, you just return a new Future.
Once you start in this path, you can't stop there. You realize that in order to manipulate two futures, you just need to model as an applicative, in order to create futures, you need a monad definition for future, etc.
UPDATE: As suggested by #Eric, I've written a blog post: http://www.tikalk.com/incubator/blog/functional-programming-scala-rest-us
I finally understood how applicatives can help in day-to-day programming with that presentation:
https://web.archive.org/web/20100818221025/http://applicative-errors-scala.googlecode.com/svn/artifacts/0.6/chunk-html/index.html
The autor shows how applicatives can help for combining validations and handling failures.
The presentation is in Scala, but the author also provides the full code example for Haskell, Java and C#.
Warning: my answer is rather preachy/apologetic. So sue me.
Well, how often in your day-to-day Haskell programming do you create new data types? Sounds like you want to know when to make your own Applicative instance, and in all honesty unless you are rolling your own parser, you probably won't need to do it very much. Using applicative instances, on the other hand, you should learn to do frequently.
Applicative is not a "design pattern" like decorators or strategies. It is an abstraction, which makes it much more pervasive and generally useful, but much less tangible. The reason you have a hard time finding "practical uses" is because the example uses for it are almost too simple. You use decorators to put scrollbars on windows. You use strategies to unify the interface for both aggressive and defensive moves for your chess bot. But what are applicatives for? Well, they're a lot more generalized, so it's hard to say what they are for, and that's OK. Applicatives are handy as parsing combinators; the Yesod web framework uses Applicative to help set up and extract information from forms. If you look, you'll find a million and one uses for Applicative; it's all over the place. But since it's so abstract, you just need to get the feel for it in order to recognize the many places where it can help make your life easier.
I think Applicatives ease the general usage of monadic code. How many times have you had the situation that you wanted to apply a function but the function was not monadic and the value you want to apply it to is monadic? For me: quite a lot of times!
Here is an example that I just wrote yesterday:
ghci> import Data.Time.Clock
ghci> import Data.Time.Calendar
ghci> getCurrentTime >>= return . toGregorian . utctDay
in comparison to this using Applicative:
ghci> import Control.Applicative
ghci> toGregorian . utctDay <$> getCurrentTime
This form looks "more natural" (at least to my eyes :)
Coming at Applicative from "Functor" it generalizes "fmap" to easily express acting on several arguments (liftA2) or a sequence of arguments (using <*>).
Coming at Applicative from "Monad" it does not let the computation depend on the value that is computed. Specifically you cannot pattern match and branch on a returned value, typically all you can do is pass it to another constructor or function.
Thus I see Applicative as sandwiched in between Functor and Monad. Recognizing when you are not branching on the values from a monadic computation is one way to see when to switch to Applicative.
Here is an example taken from the aeson package:
data Coord = Coord { x :: Double, y :: Double }
instance FromJSON Coord where
parseJSON (Object v) =
Coord <$>
v .: "x" <*>
v .: "y"
There are some ADTs like ZipList that can have applicative instances, but not monadic instances. This was a very helpful example for me when understanding the difference between applicatives and monads. Since so many applicatives are also monads, it's easy to not see the difference between the two without a concrete example like ZipList.
I think it might be worthwhile to browse the sources of packages on Hackage, and see first-handedly how applicative functors and the like are used in existing Haskell code.
I described an example of practical use of the applicative functor in a discussion, which I quote below.
Note the code examples are pseudo-code for my hypothetical language which would hide the type classes in a conceptual form of subtyping, so if you see a method call for apply just translate into your type class model, e.g. <*> in Scalaz or Haskell.
If we mark elements of an array or hashmap with null or none to
indicate their index or key is valid yet valueless, the Applicative
enables without any boilerplate skipping the valueless elements while
applying operations to the elements that have a value. And more
importantly it can automatically handle any Wrapped semantics that
are unknown a priori, i.e. operations on T over
Hashmap[Wrapped[T]] (any over any level of composition, e.g. Hashmap[Wrapped[Wrapped2[T]]] because applicative is composable but monad is not).
I can already picture how it will make my code easier to
understand. I can focus on the semantics, not on all the
cruft to get me there and my semantics will be open under extension of
Wrapped whereas all your example code isn’t.
Significantly, I forgot to point out before that your prior examples
do not emulate the return value of the Applicative, which will be a
List, not a Nullable, Option, or Maybe. So even my attempts to
repair your examples were not emulating Applicative.apply.
Remember the functionToApply is the input to the
Applicative.apply, so the container maintains control.
list1.apply( list2.apply( ... listN.apply( List.lift(functionToApply) ) ... ) )
Equivalently.
list1.apply( list2.apply( ... listN.map(functionToApply) ... ) )
And my proposed syntactical sugar which the compiler would translate
to the above.
funcToApply(list1, list2, ... list N)
It is useful to read that interactive discussion, because I can't copy it all here. I expect that url to not break, given who the owner of that blog is. For example, I quote from further down the discussion.
the conflation of out-of-statement control flow with assignment is probably not desired by most programmers
Applicative.apply is for generalizing the partial application of functions to parameterized types (a.k.a. generics) at any level of nesting (composition) of the type parameter. This is all about making more generalized composition possible. The generality can’t be accomplished by pulling it outside the completed evaluation (i.e. return value) of the function, analogous to the onion can’t be peeled from the inside-out.
Thus it isn’t conflation, it is a new degree-of-freedom that is not currently available to you. Per our discussion up thread, this is why you must throw exceptions or stored them in a global variable, because your language doesn’t have this degree-of-freedom. And that is not the only application of these category theory functors (expounded in my comment in moderator queue).
I provided a link to an example abstracting validation in Scala, F#, and C#, which is currently stuck in moderator queue. Compare the obnoxious C# version of the code. And the reason is because the C# is not generalized. I intuitively expect that C# case-specific boilerplate will explode geometrically as the program grows.