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

which can be used for example:

getChars :: Int -> IO String
getChars n = sequenceA (replicate n getChar)

replicate n getChar outputs [getChar, getChar, ...] of type [IO Char].

What does sequenceA (replicate n getChar) do ?

In general what does sequenceA do?

AJF
  • 11,767
  • 2
  • 37
  • 64
Tim
  • 1
  • 141
  • 372
  • 590
  • What's with the random spacing? – melpomene Jul 27 '19 at 14:30
  • 6
    The code uses tabs in _every single space_. As a general rule, tabs break the Haskell parser, so you shouldn't use them _at all_. I've edited the code to use spaces and more consistent spacing in general. – AJF Jul 27 '19 at 14:59
  • 7
    `sequenceA` is described and explained in the [prelude documentation on Hackage](https://hackage.haskell.org/package/base-4.12.0.0/docs/Prelude.html#v:sequenceA) as well as [various past questions](https://stackoverflow.com/questions/34629132/how-sequencea-works). This question is lacking in research effort. – AJF Jul 27 '19 at 15:01
  • according to what you wrote in a recent question, `sequenceA (x:xs) = pure (:) <*> x <*> sequenceA xs = liftA2 (:) x (sequenceA xs) = [ x : xs | x <- x, xs <- sequenceA xs]`. thus `sequenceA (replicate 3 getChar) = [ x : xs | x <- getChar, xs <- sequenceA [getChar,getChar]] = [[x,y,z] | x <- getChar, y <- getChar, z <- getChar]`. this uses MonadComprehensions. – Will Ness Jul 27 '19 at 17:48
  • @WillNess Thanks. (1) How did you get `liftA2 (:) x (sequenceA xs) = [ x : xs | x <- x, xs <- sequenceA xs]`? (2) What is monad comprehension? – Tim Jul 27 '19 at 23:03
  • @Tim For (2), it’s a language extension allowing list comprehensions to be used for arbitrary monads. As for (1), it’s a simple equivalence originating from the definitions of `liftA2` and monad comprehensions. – bradrn Jul 27 '19 at 23:18
  • @bradrn Is the result of monad comprehension a list? Since it is a generalization of list comprehension, is it correct that it shouldn't output list? But `[ x : xs | x <- x, xs <- sequenceA xs]` seems to be a list. – Tim Jul 28 '19 at 02:15
  • @Tim The result of a monad comprehension is whatever monad you’re using. If `x` and `xs` are lists, then `[ x : xs | x <- x, xs <- sequenceA xs]` will also be a list. If they’re some other monad, the output will also be that monad. – bradrn Jul 28 '19 at 02:30
  • @bradrn So `[...]` in `[ x : xs | x <- x, xs <- sequenceA xs]` doesn't necessarily mean list, and different from `[...]` (which represents a list) in Haskell language? – Tim Jul 28 '19 at 02:38
  • 1
    @Tim It depends. List comprehensions were originally designed only for lists, so I presume that `[...]` originally denoted that it was a _list_ comprehension. By default, this is what Haskell uses. However, if you enable the `MonadComprehensions` extension, then you can use the same syntax for arbitrary monads. So if you use that extension, `[...]` is best thought of as just part of the syntax than having any particular meaning. – bradrn Jul 28 '19 at 02:41
  • @Tim "Is the result of monad comprehension a list?" why don't you try `GHCi> :set -XMonadComprehensions` ; `GHCi> :t [[x,y,z] | x <- getChar, y <- getChar, z <- getChar]` and find out? -- Googling ["MonadComprehensions"](https://www.google.com/search?q=MonadComprehensions) leads to e.g. https://gitlab.haskell.org/ghc/ghc/wikis/monad-comprehensions. – Will Ness Jul 28 '19 at 04:15
  • then there's [the original paper](https://ncatlab.org/nlab/files/WadlerMonads.pdf) and [the docs](https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/glasgow_exts.html?highlight=parallellist#monad-comprehensions). – Will Ness Jul 28 '19 at 07:39
  • as to the *why*, `pure (:) <*> x = (:) <$> x = fmap (:) x` and hence `pure (:) <*> x <*> sequenceA xs = fmap (:) x <*> sequenceA xs = {- by def of <*> -} do { fx <- fmap (:) x ; xs <- sequenceA xs; return fx xs } = do { x <- x ; let fx = (:) x ; xs <- sequenceA xs; return fx xs } = do { x <- x ; xs <- sequenceA xs; return (x : xs) } = [ (x : xs) | x <- x, xs <- sequenceA xs]`. All the above of course only holds for such Applicative Functors that are also Monads. Such that are not, have to implement it directly. But it is nevertheless illuminating to see these translations, I think. – Will Ness Jul 28 '19 at 08:19

2 Answers2

3

sequenceA (replicate n getChar) will wait for n characters from standard input and return them as String (list of Char) wrapped into IO. sequenceA will just evaluate (run in case of IO) the actions in the traversable and collect the results.

mariusz-r
  • 56
  • 3
1

(This answer assumes you know what an Applicative is; if you don’t, Learn You a Haskell may be a useful resource.)

Roughly speaking, sequenceA is a method of taking several Applicative values and running them. To start, let’s have a look at its type signature. You’ve defined a restricted version, but the full type signature is:

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

In general, Haskell allows you to learn a lot about a function from its type signature alone, and this is no exception. To start, let’s have a look at its input and output: it takes as input a Traversable containing Applicative elements, and returns an Applicative containing Traversible elements.

Now, how can we get from t (f a) to f (t a)? This may be easier to understand if you specialise t to [], as that is an instance of Traversible:

sequenceA :: (Applicative f) => [f a] -> f [a]

Now this starts to make more sense: given a list of f as, extract the as and return them as a list. The idea is that a value of type f x, where f is an Applicative, is an effectful value: a value which could potentially have some side-effects, but then returns a value of type x. So sequenceA acts to accumulate effects: if you have a list of effectful values [f a], then sequenceA takes each f a in sequence, runs its effect, then returns all the as together. It returns these values as an effectful list, since to return [a] it has to run the effects inside the original list.

Now let’s go back to the original definition:

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

We can interpret this in the same way: given a set of effectful values inside a Traversible data structure, sequenceA returns an effectful value created by running all the effects inside the Traversible in turn, then taking the return value thus generated and putting it back inside the Traversible. The idea of ‘in turn’ is very important: in some sense, the Traversible instance (and hence sequenceA, as one of its methods) creates the idea of an order inside a data structure, since there aren’t really any other Haskell functions which iterate over a data structure in some particular order.

Now, we can finally understand your example! Let’s consider what sequenceA (replicate n getChar) does:

  • As you noted, replicate n getChar repeats a list of [getChar, getChar, ..., getChar] n times.
  • From the above description:

    sequenceA returns an effectful value created by running all the effects inside the Traversible in turn, then taking the return value thus generated and putting it back inside the Traversible.

    So here, we take the list of getChars, run each effectful value (which has the effect of getting a character from the user and returning it), then taking the return value (i.e. the user’s character) and putting it back inside the Traversible (i.e. putting the return values back in a list).

So sequenceA (replicate n getChar) just gets n characters from the user, then returns them in a list.

It’s worth noting that this is far from the only use for sequenceA. A small sample:

  • The Applicative instance for lists takes each pair in turn from the give lists. For instance, (,) <$> [1,2] <*> ['a','b'] returns [(1,'a'),(1,'b'),(2,'a'),(2,'b')]. So sequenceA [list1, list2, ...] gets all combinations of elements i.e. the cartesian produce! For example, sequenceA [['a','b'], ['c','d'], ['e','f']] ‘runs’ the applicative by returning each combination, and then puts the results back in a list, giving ["ace","acf","ade","adf","bce","bcf","bde","bdf"].
  • In general, any time you have a collection of effects you want to run, you should be reaching for sequenceA. (Or its close relative traverse.) For example, recently I was writing a cellular automaton simulation program, and I had ended up with a data structure representing a grid with random elements. Since I was using the MonadRandom package, my randomness was represented as an Applicative, so I could use sequenceA to run each random value in turn and turn a ‘grid of random values’ into a ‘random grid of values’, which was much easier to work with.
bradrn
  • 8,337
  • 2
  • 22
  • 51