Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Non type-variable argument in the constraint when using >>= operator

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 .. >>= ...
like image 585
Marco Scabbiolo Avatar asked Apr 07 '17 00:04

Marco Scabbiolo


Video Answer


1 Answers

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 .. >>= ...)
like image 200
Alec Avatar answered Oct 05 '22 23:10

Alec