Question

I've just found Const in the documentation of Control.Applicative, but I have a hard time working out where this is useful, over just using Monoid directly.

What am I missing?

Was it helpful?

Solution

It's rather useful when combined with Traversable.

getConst . traverse Const :: (Monoid a, Traversable f) => f a -> a

That's the general recipe for glomming a bunch of stuff together. It was one of the use cases which convinced me that it was worth separating Applicative from Monad. I needed stuff like generalized elem

elem :: Eq x => x -> Term x -> Bool

to do occur-checking for a Traversable Term parametrized by the representation of free variables. I kept changing the representation of Term and I was fed up modifying a zillion traversal functions, some of which were doing accumulations, rather than effectful mapping. I was glad to find an abstraction which covered both.

OTHER TIPS

It's useful when you have a function or data structure that works for all (Applicative) Functors, and wish to reuse it in a degenerate sense. It's analogous to passing in const or id to functions that work given arbitrary functions.

Van Laarhoven lenses are defined in terms of arbitrary Functors, and use Const to derive a field accessor (and the equally trivial Identity to derive a field updater).

Traversable types, as pigworker mentions, are another example of this.

As dave4420 mentions, implementing accessor and updater for Van Laarhoven lenses involves Const functor. To elaborate:

{-# LANGUAGE Rank2Types #-}

import Control.Applicative
import Control.Monad.Identity

-- The definition of Van Laarhoven lenses:
type Lens a b = forall f . Functor f => (b -> f b) -> (a -> f a)

-- Getter passes the Const functor to the lens:
get :: Lens a b -> a -> b
get l = getConst . (l Const)

-- Updater passes the Identity functor to the lens:
modify :: Lens a b -> (b -> b) -> (a -> a)
modify l f = runIdentity . l (Identity . f)

set :: Lens a b -> b -> (a -> a)
set l r = modify l (const r)

-- Example: -------------------------------------------

data Person = Person { _name :: String, _age :: Int }
  deriving Show

name :: Lens Person String
name f (Person n a) = fmap (\x -> Person x a) (f n)

age :: Lens Person Int
age f (Person n a) = fmap (\x -> Person n x) (f a)

main :: IO ()
main = do
    let john = Person "John" 34
    print $ get age john
    print $ set name "Pete" john

As Gabriel Gonzalez points out, Const is used to provide Getters to lenses. http://hackage.haskell.org/package/lens-tutorial-1.0.0/docs/Control-Lens-Tutorial.html. There you only use that Const is a functor.

For traversals, you need the full Applicative behaviour, and it becomes what pigworker described in another answer.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top