与API对话的最佳做法

史蒂夫

我正在尝试为Haskell中的API创建一些绑定。我注意到某些函数具有大量参数,例如

myApiFunction :: Key -> Account -> Int -> String -> Int -> Int -> IO (MyType)

拥有如此多的论点本身不一定是坏事。但是作为用户,我不喜欢长参数函数。但是,这些参数中的每一个绝对是100%必需的。

是否有一种更草率的方式来抽象这些功能的公共部分?过去帐户中的所有内容都用于构建URL,因此我需要它可用,它所代表的含义完全取决于功能。但是,某些事物是一致的,例如KeyAccount,我想知道在这些参数上进行抽象的最好方法是什么。

谢谢!

比克利尔

您可以将它们组合成更具描述性的数据类型:

data Config = Config
    { cKey :: Key
    , cAccount :: Account
    }

然后可能使用type或或newtypes使其他参数更具描述性:

-- I have no idea what these actually should be, I'm just making up something
type Count = Int
type Name = String
type Position = (Int, Int)

myApiFunction :: Config -> Count -> Name -> Position -> IO MyType
myApiFunction conf count name (x, y) =
    myPreviousApiFunction (cKey conf)
                          (cAccount conf)
                          name
                          name
                          x
                          y

如果Config始终需要,那么我建议您在Readermonad中工作,您可以轻松地

myApiFunction
    :: (MonadReader Config io, MonadIO io)
    => Count -> Name -> Position
    -> io MyType
myApiFunction count name (x, y) = do
    conf <- ask
    liftIO $ myPreviousApiFunction
                (cKey conf)
                (cAccount conf)
                name
                name
                x
                y

这将mtl库用于monad变压器。如果您不想一遍又一遍地键入该约束,也可以使用ConstraintKinds扩展名对其进行别名:

{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE FlexibleContexts #-}
...

type ApiCtx io = (MonadReader Config io, MonadIO io)

...

myApiFunction
    :: ApiCtx io
    => Count -> Location -> Position
    -> io MyType
myApiFunction ...

根据您的特定应用程序,您还可以将其拆分为多个功能。在此之前,我已经看过很多API

withCount :: ApiCtx io => Count    -> io a -> io a
withName  :: ApiCtx io => Name     -> io a -> io a
withPos   :: ApiCtx io => Position -> io a -> io a

(&) :: a -> (a -> b) -> b

request :: ApiCtx io => io MyType 

> :set +m   -- Multi-line input
> let r = request & withCount 1
|                 & withName "foo"
|                 & withPos (1, 2)
> runReaderT r (Config key acct)

这些只是少数技术,还有其他一些技术,但是在此之后它们通常会变得越来越复杂。其他人对如何执行此操作会有不同的偏好,而且我敢肯定,在其中某些方法是否甚至是良好实践方面,我会与我意见相左(具体来说ConstraintKinds,它未被普遍接受)。

如果您发现自己的类型签名太大,即使应用了其中的一些技术,那么也许您是从错误的方向解决问题的,也许这些功能可以分解为更简单的中间步骤,也许其中一些这些参数可以在逻辑上分为更具体的数据类型,也许您只需要一个更大的记录结构即可处理复杂的操作。现在很开放。

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章