# Monadic Vectors

Eric Bailey

Written on 2 December, 2023

Updated on 02 January, 2024

Tags: haskell, monads, mathematics, algebra

The `Functor`

instance for 3-dimensional vectors applies a function `f`

to each
basis vector, preserving the structure of the 3-D vector.

instance Functor V3 where fmap f (V3 a b c) = V3 (f a) (f b) (f c) a <$ _ = V3 a a a

λ> fmap (+1) (V3 1 2 3) V3 2 3 4

The `Applicative`

instance provides operations to embed pure expressions
(`pure`

), and sequence computations and combine their results (`<*>`

and
`liftA2`

).
N.B. The default definition is:

`liftA2 f x y = f <$> x <*> y`

instance Applicative V3 where pure a = V3 a a a V3 a b c <*> V3 d e f = V3 (a d) (b e) (c f)

λ> pure 0 :: V3 Int V3 0 0 0 λ> V3 (+5) (+3) (+1) <*> V3 1 2 3 V3 6 5 4

Together they enable applying a binary function as follows.

λ> (+) <$> V3 1 2 3 <*> V3 4 5 6 V3 5 7 9

There's also a `Monad`

instance, which enables concise and elegant code.

instance Monad V3 where V3 a b c >>= f = V3 a' b' c' where V3 a' _ _ = f a V3 _ b' _ = f b V3 _ _ c' = f c

For example, as part of the Advent of Code puzzle for Day 2 of 2023, one must
parse revelations of the form `N COLOR`

where `N`

is a `natural`

number and
`COLOR`

is one of `red`

, `green`

, and `blue`

. The tricolor nature of the
revelations (and the subsequent computations therewith) lends itself nicely to
3-dimensional vectors.

A naive `Parser`

might look as follows.

revelation :: Parser (V3 Integer) revelation = do n <- natural V3 n 0 0 <$ string "red" <|> V3 0 n 0 <$ string "green" <|> V3 0 0 n <$ string "blue"

The `Monad`

instance, however, enables the following.

revelation :: Parser (V3 Integer) revelation = natural >>= \n -> for (V3 "red" "green" "blue") $ \color -> n <$ string color <|> pure 0

Also delightfully concise is this way of determining which games are possible.

isPossible :: [V3 Integer] -> Bool isPossible = all (and . liftA2 (>=) (V3 12 13 14))