我有这个多态代码(见这个问题),带有用于模型和客户端的通用单子:
import Control.Monad.Writer
class Monad m => Model m where
act :: Client c => String -> c a -> m a
class Monad c => Client c where
addServer :: String -> c ()
scenario1 :: forall c m. (Client c, Model m) => m ()
scenario1 = do
act "Alice" $ addServer @c "https://example.com"
这是通过 Writer monad 解释日志中操作的漂亮打印解释器Client
:
type Printer = Writer [String]
instance Client Printer where
addServer :: String -> Printer ()
addServer srv = tell [" add server " ++ srv ++ "to the client"]
的翻译Model
很难。我尝试了几件事,每件事都会导致自己的错误:
- “无法匹配类型‘c’”:
instance Model Printer where
act :: String -> Printer a -> Printer a
act name action = do
tell [name ++ ":"]
action
- “`不能将'Printer a'类型的表达式应用于可见类型参数'(Printer a)'”:
instance Model Printer where
act :: forall a. String -> Printer a -> Printer a
act name action = do
tell [name ++ ":"]
action @(Printer a)
- “无法将类型 'c' 与 'WriterT [String] Data.Functor.Identity.Identity' 匹配”
instance Model Printer where
act :: Client c => String -> c a -> Printer a
act name action = do
tell [name ++ ":"]
action
不知何故,我需要告诉现在c a
是什么。act
Printer a
也许我需要在模型类中有两个参数——m
模型单子和c
客户端单子,模型类也应该定义函数clientToModel :: c a -> m a
?
有没有办法让模型和客户端解耦?我可能还需要clientToModel :: c a -> m a
每一对?
我很感激这个建议。谢谢!