[Haskell-cafe] Two mysteries
Henry Laxen
nadine.and.henry at pobox.com
Sun Aug 28 16:36:56 UTC 2022
-- run this with ghci -package microlens-platform -package stm -package containers SC.hs
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE TemplateHaskell #-}
module Games.SC where
import qualified Data.Map.Strict as M
import GHC.IO.Unsafe ( unsafePerformIO )
import Lens.Micro.Platform
import Control.Concurrent.STM.TVar
import Control.Concurrent.STM
import Control.Monad.IO.Class
type Lenstype f a b = (b -> f b) -> a -> f a
instance Show a => Show (TVar a) where
show x = unsafePerformIO $ do
sx <- readTVarIO x
return ("TVar: " <> show sx)
newtype TMap k v = TMap (TVar (M.Map k (TVar v))) deriving Show
-- TMap (TVar (Map k (TVar v)))
-- ^^^^ modify this TVar to add/delete a key
-- TMap (TVar (Map k (TVar v)))
-- ^^^^ modify this TVar to change a value
withKey :: (MonadIO m, Ord k) => k -> (Maybe v -> v) -> TMap k v -> m ()
withKey k f (TMap x) = liftIO $ do
atomically $ do
tMap <- readTVar x
let
mbK = M.lookup k tMap
case mbK of -- insert a new (key,value) into the map
Nothing -> do
v' <- newTVar (f Nothing)
let
newMap = M.insert k v' tMap
writeTVar x newMap
Just tv -> do -- modify the value of an existing key
v' <- readTVar tv
let newV = f (Just v')
writeTVar tv newV
return ()
class State a where
type StateKey a :: *
type StateValue a :: *
lensTmap :: Functor f => Lenstype f a (TMap (StateKey a) (StateValue a))
lensKey :: Functor f => Lenstype f a (StateKey a)
lensCounter :: Functor f => Lenstype f (StateValue a) Int
updateState state f = liftIO $ do
let
key = state ^. lensKey -- read the key
mutable = state ^. lensTmap -- find the TVar of the TMap
withKey key (\(Just x) -> x & lensCounter %~ f) mutable -- update it
-- THE FIRST MYSTERY: If I use the inferred type explicitly for updateState
-- above, this no longer compiles. I get a "could not deduce" error
-- reproduced below:
-- xupdateState
-- :: (MonadIO m, Ord (StateKey s), State s, State a,
-- StateValue s ~ StateValue a) =>
-- s -> (Int -> Int) -> m ()
-- xupdateState state f = liftIO $ do
-- let
-- key = state ^. lensKey -- read the key
-- mutable = state ^. lensTmap -- find the TVar of the TMap
-- withKey key (\(Just x) -> x & lensCounter %~ f) mutable -- update it
-- /home/henry/nadineloveshenry/projects/nlh/src/Games/SC.hs:84:33-43: error:
-- • Could not deduce: StateValue a0 ~ StateValue a
-- from the context: (MonadIO m, Ord (StateKey s), State s, State a,
-- StateValue s ~ StateValue a)
-- bound by the type signature for:
-- xupdateState :: forall (m :: * -> *) s a.
-- (MonadIO m, Ord (StateKey s), State s, State a,
-- StateValue s ~ StateValue a) =>
-- s -> (Int -> Int) -> m ()
-- at /home/henry/nadineloveshenry/projects/nlh/src/Games/SC.hs:(76,1)-(79,30)
-- Expected type: ASetter (StateValue a) (StateValue a) Int Int
-- Actual type: Lenstype
-- Data.Functor.Identity.Identity (StateValue a0) Int
-- NB: ‘StateValue’ is a non-injective type family
-- The type variable ‘a0’ is ambiguous
-- • In the first argument of ‘(%~)’, namely ‘lensCounter’
-- In the second argument of ‘(&)’, namely ‘lensCounter %~ f’
-- In the expression: x & lensCounter %~ f
-- • Relevant bindings include
-- x :: StateValue a
-- (bound at /home/henry/nadineloveshenry/projects/nlh/src/Games/SC.hs:84:23)
-- mutable :: TMap (StateKey s) (StateValue a)
-- (bound at /home/henry/nadineloveshenry/projects/nlh/src/Games/SC.hs:83:5)
data SampleState = SampleState
{
_key :: String
, _tMap :: TMap String SampleValue
} deriving Show
data SampleValue = SampleValue
{
_counter :: Int
, _other :: ()
} deriving Show
$(makeLenses ''SampleState)
$(makeLenses ''SampleValue)
makeSampleState :: IO SampleState
makeSampleState = do
let sampleValue = SampleValue 1 ()
tvar1 <- newTVarIO sampleValue
let sampleTMap = M.fromList [("a", tvar1)]
tvar2 <- newTVarIO sampleTMap
return (SampleState "a" (TMap tvar2))
-- I can show the result of makeSampleState:
-- λ> makeSampleState
-- SampleState {_key = "a", _tMap = TMap TVar: fromList [("a",TVar: SampleValue {_counter = 1, _other = ()})]}
bump1 :: IO ()
bump1 = do
xss <- makeSampleState
let xTmap = xss ^. tMap
withKey "a" (\(Just x) -> x & counter %~ (+1)) xTmap
print xTmap
-- Everything here is tickety-boo
-- λ> bump1
-- TMap TVar: fromList [("a",TVar: SampleValue {_counter = 2, _other = ()})]
-- Now let's make SampleState an instance of State
instance State SampleState where
type StateKey SampleState = String
type StateValue SampleState = SampleValue
lensTmap = tMap
lensKey = key
lensCounter = counter
-- THE SECOND MYSTERY: now lets try bump1 with the type family, but there is no joy
-- bump2 :: IO ()
-- bump2 = do
-- xss <- makeSampleState
-- let xTmap = xss ^. lensTmap
-- withKey "a" (\(Just x) -> x & lensCounter %~ (+1)) xTmap
-- print xTmap
-- SC.hs:163:33-43: error:
-- • Couldn't match type ‘StateValue a0’ with ‘SampleValue’
-- Expected type: ASetter SampleValue SampleValue Int Int
-- Actual type: Lenstype
-- Data.Functor.Identity.Identity (StateValue a0) Int
-- The type variable ‘a0’ is ambiguous
-- • In the first argument of ‘(%~)’, namely ‘lensCounter’
-- In the second argument of ‘(&)’, namely ‘lensCounter %~ (+ 1)’
-- In the expression: x & lensCounter %~ (+ 1)
-- Can someone please explain what is going on, or point me at a book/paper
-- Thanks in advance.
-- You can load this into ghci and uncomment to "bad" code to see for
-- yourself what happens
--
Nadine and Henry Laxen The rest is silence
Gral. Manuel Márquez de León 1301
Onix #2302
Zona Urban Rio Never try to teach a pig to sing;
Tijuana It wastes your time
+52 (333) 667-8633 And it annoys the pig
More information about the Haskell-Cafe
mailing list