Вы можете объединить их в более описательные типы данных:
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
всегда необходимо, то я бы рекомендовал работать в монаде Reader
, который вы можете легко сделать как
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
для монадных трансформаторов. Если вы не хотите, чтобы ввести это ограничение снова и снова, вы можете также использовать расширение 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
, это не принято вообще).
Если вы обнаружите, что у вас слишком много типов подписей, даже после применения некоторых из этих методов, возможно, вы приближаетесь к проблеме с неправильного направления, возможно, эти функции можно разбить на более простые промежуточные этапы , возможно, некоторые из этих аргументов могут быть объединены логически в более конкретные типы данных, возможно, вам просто нужна более крупная структура записей для обработки сложных операций. Сейчас это довольно открыто.
Объявить тип, объединяющий все эти отдельные аргументы в одно значение? (Попытка найти логические группировки - это, как правило, забавная часть.) Вы также можете определить «новый тип» или хотя бы псевдоним «type» для всех этих значений «Int». – MathematicalOrchid
Я попробовал кучу разных идей в Strive, привязав API к Страве. В конечном итоге я получил настройки и линзы. Ознакомьтесь с [этой проблемой] (https://github.com/tfausak/strive/issues/44) для обсуждения и [в этом примере] (https://github.com/tfausak/strive/tree/v1.0.1 # segment-leaderboard) для того, как это выглядит сейчас. –