5
votes

I have this simple code:

module Matrix where

matrix :: a -> (Int, Int) -> [[a]]
matrix x (width, height) = replicate height (replicate width x)

mapMatrix :: (a -> b) -> [[a]] -> [[b]]
mapMatrix f m = map (map f) m

When I do:

mapMatrix (+1) (matrix 0 (2,2))

I get, as expected:

[[1,1],[1,1]]

Probably I'm misunderstanding monads and/or the >>= operator but I was expecting the following to have the same output:

matrix 0 (2,2) >>= mapMatrix (+1)

Instead I get:

Non type-variable argument in the constraint: Num [b] (Use FlexibleContexts to permit this) When checking the inferred type It :: forall b. (Num [b], Num b) => [[b]]

How can I write mapMatrix (+1) (matrix 0 (2,2)) with monads, so I can read and write the code from left-to-right instead of in-to-out because as you can imagine, I'm planning on using mapMatrix a lot on the same matrix, something like:

matrix ... >>= mapMatrix ... >>= mapMatrix .. >>= ...
1
f x is never the same as x >>= f, just as f 1 is not the same as 1 + f: >>= is an operator that does a specific thing.amalloy
@amalloy So I'm using the wrong operator? What I'm looking for specifically is the classic bind operation that you get when using monads, at least as I learnt them in other languages. By the way I'm doing this just for learning purposes, but I could really use some guidance right nowMarco Scabbiolo
Indeed >>= is the monad bind operation but the monad bind operation doesn't seem to be what you want.user253751
Mh, I always thought of bind as bind(x, f) <=> f(x) or even x.bind(f) <=> f(x), I guess I have to learn the specifics of Haskell.Marco Scabbiolo
@MarcoScabbiolo Indeed that is not the case in general. Perhaps you are looking for (&) (in Data.Function)? That is defined as x & f = f x.Alec

1 Answers

5
votes

This not what a monad is supposed to do. You are likely interested in (&) :: a -> (a -> b) defined in Data.Function.

matrix ... & mapMatrix ... & mapMatrix .. & ...

Note that the signature of bind is

(>>=) :: m a -> (a -> m b) -> m b

and one cannot simply ignore the ms.

For completeness, note that one actually can make bind behave almost the way you want it to using one particular monad: Identity. It takes a bit of wrapping/unwrapping the constructor though.

module Matrix where

import Data.Functor.Identity

matrix :: a -> (Int, Int) -> Identity [[a]]
matrix x (width, height) = Identity $ replicate height (replicate width x)

mapMatrix :: (a -> b) -> [[a]] -> Identity [[b]]
mapMatrix f m = Identity $ map (map f) m

Then, the following works too:

runIdentity (matrix ... >>= mapMatrix ... >>= mapMatrix .. >>= ...)