如果这已经被问过/回答过很多次了,我很抱歉——我很难确定问题的实际是什么,因此不知道要搜索什么。
本质上,我定义了一个类:
class (MonadIO m) => Logger m where ...
Run Code Online (Sandbox Code Playgroud)
然后我有一个类型(我想说类型同义词,但我不确定这是否是正确的“术语”):
type ResourceOpT r m a = StateT (ResourceCache r) m a
Run Code Online (Sandbox Code Playgroud)
为什么这个实例是完全有效的:
instance (MonadIO m) => Logger ( StateT s m )
Run Code Online (Sandbox Code Playgroud)
但不是这个(我想第一个更抽象/更可取,但我试图理解为什么):
instance (MonadIO m) => Logger ( ResourceOpT r m )
Run Code Online (Sandbox Code Playgroud)
根据我的定义,两者不应该是等效的ResourceOpT吗?具体来说,我得到的错误是:
Run Code Online (Sandbox Code Playgroud)The type synonym 'ResourceOpT' should have 3 arguments, but has been given 2 In the instance declaration for 'Logger (ResourceOpT r m)'
我有一种感觉,我正在做的事情在概念上“应该”起作用,但要么我的语法错误,要么我遗漏了某些东西(可能是语言扩展),或者应该让它起作用。
无论如何,我很想得到您的意见并了解为什么这是错误的以及为什么我应该/不应该这样做。
提前致谢。
我会在序言中说,我是一名 Haskell 程序员新手(多年来偶尔对其进行修改),但在 OOO 和命令式编程方面,我已经有好几年的时间了。我目前正在学习如何使用 monad 并通过使用 monad 转换器将它们组合起来(假设我已经找到了正确的术语)。
虽然我能够将事物组装/链接在一起,但我发现很难对什么是最好的方式和风格以及如何最好地组装/编写这些交互建立直觉。
具体来说,我很想知道使用 lift/liftIO 以及两者之间的任何风味的最佳实践(或至少是你的实践)是什么,以及是否有方法(和好处)隐藏它们,因为我发现它们相当“吵闹” 。
下面是一个示例片段,我将其放在一起来说明我的意思:
consumeRenderStageGL' :: RenderStage -> StateT RenderStageContext IO ()
consumeRenderStageGL' r = do
pushDebugGroupGL (name r)
liftIO $ consumePrologueGL ( prologue r )
liftIO $ consumeEpilogueGL ( epilogue r )
consumeStreamGL ( stream r )
liftIO $ popDebugGroupGL
Run Code Online (Sandbox Code Playgroud)
它调用的一些函数利用了状态 monad :
pushDebugGroupGL :: String -> StateT RenderStageContext IO ()
pushDebugGroupGL tag = do
currentDebugMessageID <- gets debugMessageID
liftIO $ GL.pushDebugGroup GL.DebugSourceApplication (GL.DebugMessageID currentDebugMessageID) tag
modify (\fc …Run Code Online (Sandbox Code Playgroud) 我目前正在尝试使用 typeclasses & 作为练习,能够登录各种上下文(即在 IO 上下文中打印到控制台)。我首先将我的Logger实现为一个由各种用于日志记录的函数组成的类型类,我的想法是我可以为 IO monad 定义一个实例,但为其他 monad 的上下文中的其他实现留出空间。
最终结果是:
-- |Class / wrapper for convenient use within another monad.
class Logger m where
-- |Logs an error message /(prefixed with the '__[ERROR]__' tag)/
logError :: String -> m ()
-- |Logs a warning message /(prefixed with the '__[WARNING]__' tag)/
logWarning :: String -> m ()
-- |Logs a success message /(prefixed with the '__[SUCCESS]__' tag)/
logSuccess :: String -> m ()
-- |Logs …Run Code Online (Sandbox Code Playgroud)