Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Ways to apply an applicative functor multiple times

Tags:

haskell

Hello fellow Haskellers.

Let's say I have an applicative functor (not an instance of monad) I want to apply multiple times to a pure initial value. For example,

λ> Just (1+) <*> (Just (1+) <*> pure 0)
Just 2

If I want to generalize this to any number of consecutive applications, I can do it with a fold.

applyAppl :: Applicative f => f (a -> a) -> Int -> f a -> f a
applyAppl f n i = foldr (<*>) i $ replicate n f

After this definition,

λ> applyAppl (Just (1+)) 10 $ pure 0
Just 10

I have an awkward suspicion that the generalization could also be done with one of the higher-order builtin applicative tools such as sequenceA or traverse. Can it?

(Edited to take into account the first two comments below.)

like image 385
jhu Avatar asked Dec 05 '17 05:12

jhu


People also ask

Is applicative a functor?

Applicative functors are the programming equivalent of lax monoidal functors with tensorial strength in category theory. Applicative functors were introduced in 2008 by Conor McBride and Ross Paterson in their paper Applicative programming with effects.

Is Fmap a functor?

The expression fmap (*2) is a function that takes a functor f over numbers and returns a functor over numbers. That functor can be a list, a Maybe , an Either String, whatever. The expression fmap (replicate 3) will take a functor over any type and return a functor over a list of elements of that type.

What is functor Monad?

A functor is a data type that implements the Functor typeclass. An applicative is a data type that implements the Applicative typeclass. A monad is a data type that implements the Monad typeclass. A Maybe implements all three, so it is a functor, an applicative, and a monad.

Is maybe a functor Haskell?

Another simple example of a functor is the Maybe type. This object can contain a value of a particular type as Just , or it is Nothing (like a null value).


1 Answers

You could use iterate:

applyAppl :: Applicative f => f (a -> a) -> Int -> f a -> f a
applyAppl f n i = iterate (f <*>) i !! n

Loaded into GHCi:

ghci> applyAppl (Just (+1)) 10 (pure 0)
Just 10

I'm not sure that's necessarily better than your implementation, since I suspect both implementations fuse into something with essentially the same performance profile (though I haven't tested that), but it is different.

I've seen this sort of "iterate with (!!)" pattern for memoization so I'm pretty sure that, at the very least, it won't have worse performance.

like image 106
David Young Avatar answered Nov 02 '22 20:11

David Young