What are practical uses of applicative style?

2019-01-30 03:41发布

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!

11条回答
Bombasti
2楼-- · 2019-01-30 04:09

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.

查看更多
唯我独甜
3楼-- · 2019-01-30 04:13

I finally understood how applicatives can help in day-to-day programming with that presentation:

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#.

查看更多
We Are One
4楼-- · 2019-01-30 04:14

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.

查看更多
来,给爷笑一个
5楼-- · 2019-01-30 04:24

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

查看更多
冷血范
6楼-- · 2019-01-30 04:25

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.

查看更多
女痞
7楼-- · 2019-01-30 04:26

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 :)

查看更多
登录 后发表回答