
-- 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

On Sun, Aug 28, 2022 at 09:36:56AM -0700, Henry Laxen wrote:
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
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 = ()})]
-- 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
This one is fairly easy to explain: `lensCounter` is a function that can work for each `a` that is an instance of `State`. So, the `lensCounter` for which `a` should it be using here? You think `a` should be `SampleState` because you've defined the following instance, and you are trying to use `lensCounter` on a value of type `SampleValue`.
instance State SampleState where type StateKey SampleState = String type StateValue SampleState = SampleValue lensTmap = tMap lensKey = key lensCounter = counter
But, suppose someone had also defined the following instance
instance State () where type StateKey () = String type StateValue () = SampleValue lensTmap = anotherTMap lensKey = anotherKey lensCounter = anotherCounter
When it comes to determine what `lensCounter` to use, `anotherCounter` would work equally well as `counter`, as would the `lensCounter` of _any_ `State` instance `a` for which `StateValue a = SampleValue`. There's no unique choice to be made here, so type checking can't proceed. There are various ways to get around this, for example making `State` a multiparameter type class and adding functional depencies. Perhaps the following will work:
class State a k v | a -> k, a -> v where lensTmap :: Functor f => Lenstype f a (TMap k v) lensKey :: Functor f => Lenstype f a k lensCounter :: Functor f => Lenstype f v Int
instance State SampleState String SampleValue where lensTmap = tMap lensKey = key lensCounter = counter
Tom

I'm probably just missing something, but in this:
-- xupdateState -- :: (MonadIO m, Ord (StateKey s), State s, State a, -- StateValue s ~ StateValue a) => -- s -> (Int -> Int) -> m () ... -- • Could not deduce: StateValue a0 ~ StateValue a ... -- The type variable ‘a0’ is ambiguous
`a` is mentioned in the constraint but isn't used in the signature. Is that the problem? Jeff
On Aug 28, 2022, at 9:36 AM, Henry Laxen
wrote: -- 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 _______________________________________________ Haskell-Cafe mailing list To (un)subscribe, modify options or view archives go to: http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe Only members subscribed via the mailman list are allowed to post.

On Sun, Aug 28, 2022 at 09:36:56AM -0700, Henry Laxen wrote:
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
AllowAmbiguousTypes is what's allowing you to get tangled into this knot. I suggest you don't enable that extension unless you feel confident you are equipped for axe warfare. The behaviour here is as though the type checker has turned `lensCounter` in the body into `lensCounter @a` for a fresh type variable `a`, and then applied the necessary constraints to the context. Normally the type checker would notice that `a` is ambiguous and refuse to continue. AllowAmbiguousTypes defers that check to the use site. That means I don't think it makes any difference to you, because even though `updateState` with inferred type signature will compile I bet you can't use it. Give it a try! I guess you'll get an "ambiguous type" error at the use site. Tom
participants (3)
-
Henry Laxen
-
Jeff Clites
-
Tom Ellis