无法以无标记最终方式/使用类型类和实例对我的组件进行编码

问题描述 投票:0回答:0

(这是我如何有条件地声明一个实例的具体案例?

在我的小项目中,玩家可以创建/加入/观看游戏会话或列出正在进行的会话。一个非常简单的 Yesod 应用程序公开了一些端点以匹配用例。

Step 1)我想抽象出“能够举办多个正在进行的比赛”的概念:

class Host m k s where
  create :: s -> m k
  read :: k -> m s
  write :: k -> s -> m ()
  update :: (s -> s) -> k -> m ()
  delete :: k -> m ()

Host m k s
的实例意味着
m
可以承载
s
的游戏(状态),由
k
识别(键控)。

Step 2) 一个非常实用的主机是共享

Map
:

newtype InMemory k s a = InMemory {run :: TVar (M.Map k s) -> STM a}

持有

TVar
Map k s
InMemory
中被捕获。
InMemory
键控
Int
可以主持:

instance Host (InMemory Int a) Int a where
  create s = InMemory $ \tvar -> do
    id <- succ . M.size <$> readTVar tvar
    modifyTVar tvar (M.insert id s)
    return id

  read id = InMemory $ \tvar -> do
    s <- M.lookup id <$> readTVar tvar
    maybe err return s
    where
      err = throwSTM $ NotFound id

  write id s = modify $ M.insert id s -- modify is just a small helper, returns InMemory
  update f id = modify $ M.update (Just . f) id
  delete id = modify $ M.delete id

步骤 3) 任何可以生成正确 tvar 的

m
也是主机。例如,Yesod 应用程序可以使
HandlerFor
成为主机:

newtype App = App {rooms :: TVar (M.Map Int Game)} -- (1)
instance MonadReader (HandlerFor App) (M.Map Int Game) where ... -- (2) HandlerFor App can produce the correct tvar
-- (1) && (2) ==> the HandlerFor App is a Host

所以让我们有这个概念:

-- smt is a just a small helper, needs MonadIO

-- this instance declaration is *wrong* and not what I want to say
instance (C.MonadIO m, R.MonadReader (TVar (M.Map k s)) m) => Host m GameId s where
  create s = GameId <$> stm (create s)
  write (GameId id) s = stm (write id s)
  update f (GameId id) = stm (update f id)
  delete (GameId id) = stm (delete id)
  read (GameId id) = stm (read id)

想法是任何可以产生正确数据的

m
都可以托管。

不麻烦来了。这个:

instance R.MonadReader (TVar (M.Map k s)) m => Host m GameId s where

不是说“如果

m
满足上下文那么它可以托管”,而是说“所有
m
是主机必须满足上下文”这不是我想说的。所以我坚持在 Haskell 中表达以下内容:

IF

m
满足上下文 THEN 它可以托管,如果不满足则此行具有 abs。没有任何效果。不要在
m
上强制上下文,如果
m
可以托管但不满足上下文,这不是错误。

关于这个主题本身就有一个问题(如何选择加入一个实例,但在其他方面不受干扰),显然这在 Haskell 中是不可能表达的。所以问题是:

  1. 我在这里有什么选择?
  2. 在我的思考过程中(1,2 和 3)我哪里出了问题,让我走入了死胡同?
  3. 正确的思考方式是什么?
haskell typeclass tagless-final
© www.soinside.com 2019 - 2024. All rights reserved.