Two almost identical functions using STArray: why does one requires FlexibleContexts, and the other does not?
You can check which type GHC assigns to f
in GHCi:
ghci> import Data.Array
ghci> import Data.Array.MArray
ghci> let arr :: STArray s Int Int; arr = undefined
ghci> :t \i -> do writeArray arr i (2*i); readArray arr i
\i -> do writeArray arr i (2*i); readArray arr i
:: (MArray (STArray s1) Int m, MArray (STArray s2) Int m) =>
Int -> m Int
This is more general than the type you suggest in your comments and the reason that FlexibleContexts
are needed.
You can add the type signature you suggested (Int -> ST s Int
) to avoid having to use FlexibleContexts
:
{-# LANGUAGE ScopedTypeVariables #-}
...
test :: forall s. ST s [Int]
test = do
arr <- newListArray (0,9) [0..9] :: ST s (STArray s Int Int)
let
f :: Int -> ST s Int
f i = do
writeArray arr i (2*i)
readArray arr i
forM [1,2] f
Note that scoped type variables and the forall s.
are necessary here because you need to make sure that the s
in all the type signatures refer to the same type variable and do not all introduce new type variables.
The reason that the monomorphism restriction treats your first and your second version differently is because it doesn't apply to things that look like functions. In your first version f
has an argument, so it looks like a function and therefore will get a general type. In your second version f
doesn't have arguments, so it doesn't look like a function which means that the monomorphism restriction forces it to have a more specific type.