处理程序和 Monad
Handler and Monads
我正在努力创作 Servant
's Handler
和 Monad
:
class Monad p => Persist p where
data Configuration p :: *
runPersistance :: Configuration p -> p a -> IO a
initPersistence :: p ()
newKind :: Kind -> p NewKindStatus
-- ...
kind :: P.Persist p => KindUid -> KindBody -> p (Handler ())
kind (KindUid uid) (KindBody actions) = undefined
subject :: P.Persist p => KindUid -> SubjectUid -> EventData -> p (Handler EventUid)
subject kind subject body = undefined
event = post :<|> get
where post :: P.Persist p => KindUid -> SubjectUid -> Action -> EventData -> p (Handler EventUid)
post kind subject action body = undefined
get :: P.Persist p => KindUid -> SubjectUid -> p (Handler [Event])
get kind subject = undefined
server :: P.Persist p => p (Server HermesAPI)
server = do
k <- kind
s <- subject
e <- event
return $ k :<|> s :<|> e
app :: P.Persist p => p (Application)
app = serve hermesAPI server
为了回答一条路线,我必须使用 P.Persist
,即 Monad
做 IO
。
我没有找到使server
编译的方法:
/app/Main.hs:55:3: error:
• Couldn't match type ‘KindUid
-> SubjectUid -> p0 (Handler [Event])’
with ‘(KindUid
-> SubjectUid -> Action -> EventData -> Handler EventUid)
:<|> (KindUid -> SubjectUid -> Handler [Event])’
Expected type: p (Server HermesAPI)
Actual type: p ((KindUid -> KindBody -> Handler ())
:<|> ((KindUid -> SubjectUid -> EventData -> Handler EventUid)
:<|> (KindUid -> SubjectUid -> p0 (Handler [Event]))))
• In a stmt of a 'do' block: k <- kind
In the expression:
do k <- kind
s <- subject
e <- event
return $ k :<|> s :<|> e
In an equation for ‘server’:
server
= do k <- kind
s <- subject
e <- event
....
|
55 | k <- kind
| ^^^^^^^^^
app/Main.hs:55:8: error:
• Couldn't match type ‘KindBody’ with ‘KindUid’
Expected type: p (KindUid -> KindBody -> Handler ())
Actual type: KindUid -> KindBody -> KindBody -> Handler ()
• In a stmt of a 'do' block: k <- kind
In the expression:
do k <- kind
s <- subject
e <- event
return $ k :<|> s :<|> e
In an equation for ‘server’:
server
= do k <- kind
s <- subject
e <- event
....
|
55 | k <- kind
| ^^^^
因为 Handler
已经是 newtype
,我卡住了。
我如何组合 Handler
和我的 Monad
以便 运行 它在 Servant 中?
编辑:
感谢 Mark Seemann,我做了一个步骤,提升 Handler
以利用 ServerT
:
newtype LiftHandler p a = LiftHandler (p (Handler a))
server :: P.Persist p => ServerT HermesAPI (LiftHandler p)
server = LiftHandler kind :<|> LiftHandler subject :<|> LiftHandler event
导致:
app/Main.hs:55:22: error:
• Couldn't match type ‘KindBody -> p2 (Handler ())’
with ‘Handler a2’
Expected type: KindUid -> Handler a2
Actual type: KindUid -> KindBody -> p2 (Handler ())
• Probable cause: ‘kind’ is applied to too few arguments
In the first argument of ‘LiftHandler’, namely ‘kind’
In the first argument of ‘(:<|>)’, namely ‘LiftHandler kind’
In the expression:
LiftHandler kind :<|> LiftHandler subject :<|> LiftHandler event
|
55 | server = LiftHandler kind :<|> LiftHandler subject :<|> LiftHandler event
谢谢。
这只是解决方案的草图,但您可能会发现这些提示很有用。 Handler
是 newtype
对 ExceptT ServerError IO a
的包装,但有时,您可能无法直接生成这样的类型。
但是,如果您有另一个 Monad
(比如您的 Persist
),您可以先使用那个 Monad
定义您的 API,然后使用 hoistServer
转换为 ExceptT ServerError IO a
.
因此,想象一下,例如,您使用以下类型定义 server
:
server :: ServerT API P.Persist
您应该可以像这样将其转换为 Server
和 运行:
run port $ serve api $ hoistServer api (Handler . trans) $ server
其中 trans
是您从 P.Persist
到 ExceptT ServerError IO
的转变。
正如 hoistServer
的 the documentation 所说:
Sometimes our cherished Handler monad isn't quite the type you'd like for your handlers.
我没有尝试编译我的任何代码草图,因此可能存在类型错误。我不知道 P.Persist
是什么,所以我无法重现这个问题。
您也可以将 server
定义为
server :: ServerT API (ExceptT ServantErr P.Persist)
以便您可以使用 throwError
传达 HTTP(错误)状态代码。这也可能使编写从 ExceptT ServantErr P.Persist
到 ExceptT ServerError IO
的转换变得更容易,因为现在你只需要弄清楚如何将 P.Persist
转换为 IO
.
我正在努力创作 Servant
's Handler
和 Monad
:
class Monad p => Persist p where
data Configuration p :: *
runPersistance :: Configuration p -> p a -> IO a
initPersistence :: p ()
newKind :: Kind -> p NewKindStatus
-- ...
kind :: P.Persist p => KindUid -> KindBody -> p (Handler ())
kind (KindUid uid) (KindBody actions) = undefined
subject :: P.Persist p => KindUid -> SubjectUid -> EventData -> p (Handler EventUid)
subject kind subject body = undefined
event = post :<|> get
where post :: P.Persist p => KindUid -> SubjectUid -> Action -> EventData -> p (Handler EventUid)
post kind subject action body = undefined
get :: P.Persist p => KindUid -> SubjectUid -> p (Handler [Event])
get kind subject = undefined
server :: P.Persist p => p (Server HermesAPI)
server = do
k <- kind
s <- subject
e <- event
return $ k :<|> s :<|> e
app :: P.Persist p => p (Application)
app = serve hermesAPI server
为了回答一条路线,我必须使用 P.Persist
,即 Monad
做 IO
。
我没有找到使server
编译的方法:
/app/Main.hs:55:3: error:
• Couldn't match type ‘KindUid
-> SubjectUid -> p0 (Handler [Event])’
with ‘(KindUid
-> SubjectUid -> Action -> EventData -> Handler EventUid)
:<|> (KindUid -> SubjectUid -> Handler [Event])’
Expected type: p (Server HermesAPI)
Actual type: p ((KindUid -> KindBody -> Handler ())
:<|> ((KindUid -> SubjectUid -> EventData -> Handler EventUid)
:<|> (KindUid -> SubjectUid -> p0 (Handler [Event]))))
• In a stmt of a 'do' block: k <- kind
In the expression:
do k <- kind
s <- subject
e <- event
return $ k :<|> s :<|> e
In an equation for ‘server’:
server
= do k <- kind
s <- subject
e <- event
....
|
55 | k <- kind
| ^^^^^^^^^
app/Main.hs:55:8: error:
• Couldn't match type ‘KindBody’ with ‘KindUid’
Expected type: p (KindUid -> KindBody -> Handler ())
Actual type: KindUid -> KindBody -> KindBody -> Handler ()
• In a stmt of a 'do' block: k <- kind
In the expression:
do k <- kind
s <- subject
e <- event
return $ k :<|> s :<|> e
In an equation for ‘server’:
server
= do k <- kind
s <- subject
e <- event
....
|
55 | k <- kind
| ^^^^
因为 Handler
已经是 newtype
,我卡住了。
我如何组合 Handler
和我的 Monad
以便 运行 它在 Servant 中?
编辑:
感谢 Mark Seemann,我做了一个步骤,提升 Handler
以利用 ServerT
:
newtype LiftHandler p a = LiftHandler (p (Handler a))
server :: P.Persist p => ServerT HermesAPI (LiftHandler p)
server = LiftHandler kind :<|> LiftHandler subject :<|> LiftHandler event
导致:
app/Main.hs:55:22: error:
• Couldn't match type ‘KindBody -> p2 (Handler ())’
with ‘Handler a2’
Expected type: KindUid -> Handler a2
Actual type: KindUid -> KindBody -> p2 (Handler ())
• Probable cause: ‘kind’ is applied to too few arguments
In the first argument of ‘LiftHandler’, namely ‘kind’
In the first argument of ‘(:<|>)’, namely ‘LiftHandler kind’
In the expression:
LiftHandler kind :<|> LiftHandler subject :<|> LiftHandler event
|
55 | server = LiftHandler kind :<|> LiftHandler subject :<|> LiftHandler event
谢谢。
这只是解决方案的草图,但您可能会发现这些提示很有用。 Handler
是 newtype
对 ExceptT ServerError IO a
的包装,但有时,您可能无法直接生成这样的类型。
但是,如果您有另一个 Monad
(比如您的 Persist
),您可以先使用那个 Monad
定义您的 API,然后使用 hoistServer
转换为 ExceptT ServerError IO a
.
因此,想象一下,例如,您使用以下类型定义 server
:
server :: ServerT API P.Persist
您应该可以像这样将其转换为 Server
和 运行:
run port $ serve api $ hoistServer api (Handler . trans) $ server
其中 trans
是您从 P.Persist
到 ExceptT ServerError IO
的转变。
正如 hoistServer
的 the documentation 所说:
Sometimes our cherished Handler monad isn't quite the type you'd like for your handlers.
我没有尝试编译我的任何代码草图,因此可能存在类型错误。我不知道 P.Persist
是什么,所以我无法重现这个问题。
您也可以将 server
定义为
server :: ServerT API (ExceptT ServantErr P.Persist)
以便您可以使用 throwError
传达 HTTP(错误)状态代码。这也可能使编写从 ExceptT ServantErr P.Persist
到 ExceptT ServerError IO
的转换变得更容易,因为现在你只需要弄清楚如何将 P.Persist
转换为 IO
.