Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

GHC rejects ST monad code as unable to unify type variables?

I wrote the following function:

(.>=.) :: Num a => STRef s a -> a -> Bool
r .>=. x = runST $ do
 v <- readSTRef r
 return $ v >= x

but when I tried to compile I got the following error:

Could not deduce (s ~ s1)
from the context (Num a)
  bound by the type signature for
             .>=. :: Num a => STRef s a -> a -> Bool
  at test.hs:(27,1)-(29,16)
  `s' is a rigid type variable bound by
      the type signature for .>=. :: Num a => STRef s a -> a -> Bool
      at test.hs:27:1
  `s1' is a rigid type variable bound by
       a type expected by the context: ST s1 Bool at test.hs:27:12
Expected type: STRef s1 a
  Actual type: STRef s a
In the first argument of `readSTRef', namely `r'
In a stmt of a 'do' expression: v <- readSTRef r

Can anyone help?

like image 509
user1023733 Avatar asked Nov 04 '11 09:11

user1023733


2 Answers

This is exactly as intended. An STRef is only valid in one run of runST. And you try to put an external STRef into a new run of runST. That is not valid. That would allow arbitrary side-effects in pure code.

So, what you try is impossible to achieve. By design!

like image 54
jmg Avatar answered Sep 23 '22 21:09

jmg


You need to stay within the ST context:

(.>=.) :: Ord a => STRef s a -> a -> ST s Bool
r .>=. x = do
 v <- readSTRef r
 return $ v >= x

(And as hammar points out, to use >= you need the Ord typeclass, which Num doesn't provide.)

like image 21
dave4420 Avatar answered Sep 25 '22 21:09

dave4420