Haskell / Wreq - 关于 http 请求的复杂类型签名的建议
Haskell / Wreq - Advice on complicated type signatures for http requests
我是一个 Haskell 初学者,目前正在使用 wreq 围绕 api 制作一个简单的包装器。如果有时间,我想发送 if-modified-since
header。我按以下方式这样做。
getResponse :: (FormatTime t, Exception e) => File -> Maybe t -> IO (Either e (Response L.ByteString))
getResponse file (Just t) =
let formattedTime = (B.pack . formatTime defaultTimeLocale rfc822DateFormat) t
opts = defaults & header "if-modified-since" .~ [formattedTime]
in try $ getWith opts $ buildUrl file
getResponse file Nothing = try $ (get $ buildUrl file)
我注意到 304 (not modified)
响应作为异常返回,因此这是我使用 Either
类型的理由。我想为可能使用此 api 包装器的人提供错误可见性。
假设请求成功,我想将响应 body 解析为我的库中定义的相应类型。如果我向其发出请求的服务器发生某些变化,反序列化可能无法正常工作,因此我选择使用 Maybe
类型来解决这个问题。
getPayload :: FromJSON b => (Either e (Response L.ByteString)) -> Either e (Maybe b)
getPayload (Left _) = return Nothing
getPayload (Right a) = return $ fmap Just (^. responseBody) =<< asJSON a
这些函数的签名开始让我觉得碍眼,我的直觉告诉我有更好的方法,但我不确定。我做的一件事是制作另一个功能将它们放在一起,希望它更容易使用。这是我计划用来创建其他函数以对单个资源提出更具体请求的函数。
getResource :: (Exception e, FormatTime t, FromJSON b) => File -> Maybe t -> IO (Either e (Maybe b))
getResource f t = getPayload <$> (getResponse f t)
我现在在处理 http 请求时必须处理 3 层结构。 IO
、Either
和 Maybe
。我是不是太复杂了?从使用和可维护性的角度来看,我该怎么做才能减轻这种工作的痛苦?我该如何改进?
这可能不是您想要的,但是 asJSON
具有 return 类型 m (Response a)
,其中 m
是 MonadThrow
。虽然 Maybe
是一个 MonadThrow
实例,但 Either e
也是。这意味着如果 asJSON
出现任何问题,您 不必 使用 Maybe
来处理。您可以 'stay' 在 Either
monad 中代替:
getPayload :: FromJSON b => Either SomeException (Response L.ByteString)
-> Either SomeException b
getPayload = ((fmap (^. responseBody) . asJSON) =<<)
显然,这对左侧的错误类型施加了额外的限制,因此我不确定这是否可以接受。如果没有,请发表评论。
我是一个 Haskell 初学者,目前正在使用 wreq 围绕 api 制作一个简单的包装器。如果有时间,我想发送 if-modified-since
header。我按以下方式这样做。
getResponse :: (FormatTime t, Exception e) => File -> Maybe t -> IO (Either e (Response L.ByteString))
getResponse file (Just t) =
let formattedTime = (B.pack . formatTime defaultTimeLocale rfc822DateFormat) t
opts = defaults & header "if-modified-since" .~ [formattedTime]
in try $ getWith opts $ buildUrl file
getResponse file Nothing = try $ (get $ buildUrl file)
我注意到 304 (not modified)
响应作为异常返回,因此这是我使用 Either
类型的理由。我想为可能使用此 api 包装器的人提供错误可见性。
假设请求成功,我想将响应 body 解析为我的库中定义的相应类型。如果我向其发出请求的服务器发生某些变化,反序列化可能无法正常工作,因此我选择使用 Maybe
类型来解决这个问题。
getPayload :: FromJSON b => (Either e (Response L.ByteString)) -> Either e (Maybe b)
getPayload (Left _) = return Nothing
getPayload (Right a) = return $ fmap Just (^. responseBody) =<< asJSON a
这些函数的签名开始让我觉得碍眼,我的直觉告诉我有更好的方法,但我不确定。我做的一件事是制作另一个功能将它们放在一起,希望它更容易使用。这是我计划用来创建其他函数以对单个资源提出更具体请求的函数。
getResource :: (Exception e, FormatTime t, FromJSON b) => File -> Maybe t -> IO (Either e (Maybe b))
getResource f t = getPayload <$> (getResponse f t)
我现在在处理 http 请求时必须处理 3 层结构。 IO
、Either
和 Maybe
。我是不是太复杂了?从使用和可维护性的角度来看,我该怎么做才能减轻这种工作的痛苦?我该如何改进?
这可能不是您想要的,但是 asJSON
具有 return 类型 m (Response a)
,其中 m
是 MonadThrow
。虽然 Maybe
是一个 MonadThrow
实例,但 Either e
也是。这意味着如果 asJSON
出现任何问题,您 不必 使用 Maybe
来处理。您可以 'stay' 在 Either
monad 中代替:
getPayload :: FromJSON b => Either SomeException (Response L.ByteString)
-> Either SomeException b
getPayload = ((fmap (^. responseBody) . asJSON) =<<)
显然,这对左侧的错误类型施加了额外的限制,因此我不确定这是否可以接受。如果没有,请发表评论。