Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How `sequenceA` works

I'm new to Haskell and trying to understand how does this work?

sequenceA [(+3),(+2),(+1)] 3

I have started from the definition

sequenceA :: (Applicative f) => [f a] -> f [a]  
sequenceA [] = pure []  
sequenceA (x:xs) = (:) <$> x <*> sequenceA xs

And then unfolded recursion into this

(:) <$> (+3) <*> $ (:) <$> (+2) <*> $ (:) <$> (+1) <*> pure [] 
(:) <$> (+3) <*> $ (:) <$> (+2) <*> $ (:) <$> (+1) <*> []

But here i don't understand for which applicative functor operator <*> will be called, for ((->) r) or for []

(:) <$> (+1) <*> []

Can somebody go step by step and parse sequenceA [(+3),(+2),(+1)] 3 step by step? Thanks.

like image 674
Yola Avatar asked Jan 06 '16 09:01

Yola


People also ask

How does sequencing work DNA?

Sequencing DNA means determining the order of the four chemical building blocks - called "bases" - that make up the DNA molecule. The sequence tells scientists the kind of genetic information that is carried in a particular DNA segment.

What are the 3 basic steps of sequencing DNA?

Next-generation sequencing involves three basic steps: library preparation, sequencing, and data analysis. Find resources to help you prepare for each step and see an example workflow for microbial whole-genome sequencing, a common NGS application.

What is A sequencing method?

DNA Sequencing is the method that determines the order of the four nucleotides bases (adenine, thymine, cytosine, and guanine) that make up the DNA molecule and convey important genetic information. In the DNA double helix, the four bases bond with the specific partner to form units called base pairs (bp).


2 Answers

This can be seen from the type of sequenceA:

sequenceA :: (Applicative f, Traversable t) => t (f a) -> f (t a)

The argument's outer type has to be a Traverable, and its inner type has to be Applicative.

Now, when you give sequenceA a list of functions (Num a) => [a -> a] the list will be the Traversable, and the things inside the list should be Applicative. Therefore, it uses the applicative instance for functions.

So when you apply sequenceA to [(+3),(+2),(+1)], the following computation is built:

sequenceA [(+3),(+2),(+1)] = (:) <$> (+3) <*> sequenceA [(+2),(+1)]
sequenceA [(+2),(+1)]      = (:) <$> (+2) <*> sequenceA [(+1)]
sequenceA [(+1)]           = (:) <$> (+1) <*> sequenceA []
sequenceA []               = pure []

Let's look at the last line. pure [] takes an empty list and puts it inside some applicative structure. As we've just seen, the applicative structure in this case is ((->) r). Because of this, sequenceA [] = pure [] = const [].

Now, line 3 can be written as:

sequenceA [(+1)] = (:) <$> (+1) <*> const []

Combining functions this way with <$> and <*> results in parallel application. (+1) and const [] are both applied to the same argument, and the results are combined using (:)

Therefore sequenceA [(+1)] returns a function that takes a Num a => a type value, applies (+1) to it, and then prepends the result to an empty list, \x -> (:) ((1+) x) (const [] x) = \x -> [(+1) x].

This concept can be extended further to sequenceA [(+3), (+2), (+1)]. It results in a function that takes one argument, applies all three functions to that argument, and combines the three results with (:) collecting them in a list: \x -> [(+3) x, (+2) x, (+1) x].

like image 96
Thomas Smith Avatar answered Oct 14 '22 16:10

Thomas Smith


it is using instance Applicative ((->) a).

Try this in ghci:

Prelude> :t [(+3),(+2),(+1)]
[(+3),(+2),(+1)] :: Num a => [a -> a]

Prelude> :t sequenceA
sequenceA :: (Applicative f, Traversable t) => t (f a) -> f (t a)

and pattern match the argument type: t = [], f = (->) a and the Applicative constraint is on f.

like image 40
d8d0d65b3f7cf42 Avatar answered Oct 14 '22 18:10

d8d0d65b3f7cf42