You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Safe use of unsafeFreeze in arbitrary PrimMonad #431
As it turns out use of unsafeFreeze (for whatever array library) together with polymorphic PrimMonad allows to violate referential transparency using seemingly reasonable code. Let consider following pseudocode:
do v <- newArray 2
write v 0=<< action0
write v 1=<< action1
unsafeFreeze v
It looks perfectly safe and it is safe for some monads like IO,ST, transfomers like Writer/Reader/State. Yet for monads which allow backtracking it allows to break referential transparency. Here's examples using ListT from list-t and ContT monads and vector package:
{-# LANGUAGE TypeFamilies #-}
moduleQwhereimportControl.ApplicativeimportControl.DeepSeqimportControl.Monad.PrimitiveimportControl.Monad.Trans.ClassimportControl.Monad.Trans.ContimportData.Vector.UnboxedqualifiedasVUimportData.Vector.Unboxed.MutablequalifiedasVUMimportListT (ListT(..), toList)
instancePrimMonadm=>PrimMonad (ListTm) wheretypePrimState (ListTm) =PrimStatem
primitive = lift . primitive
horror::IO [([Int], VU.VectorInt)]
horror =ListT.toList $do
mv <-VUM.replicateM 2$pure0<|>pure1
v <-VU.unsafeFreeze mv
let!i = force $VU.toList v
pure (i,v)
liftList::Monadm=> [a] ->ContT [r] ma
liftList xs =ContT$\cnt ->concat<$>traverse cnt xs
continuedHorror::IO [([Int], VU.VectorInt)]
continuedHorror =flip runContT (pure.pure) $do
mv <-VUM.replicateM 2$ liftList [0, 1]
v <-VU.unsafeFreeze mv
let!i = force $VU.toList v
pure (i,v)
It's not surprising since we have 4 vectors sharing same buffer.
But this pattern is clearly useful. So it would be nice to have type class with laws which tell that such use of unsafeFreeze is safe. Informally it's clear: no backtracking but I would like to have law with firmer footing.
This issue was brought up during discussions about implementation of unstreamM variant which writes directly to vector. See haskell/vector#416 and haskell/vector#544 for discussion
Activity