haskell - Best practices for talking to an API -
i'm trying create bindings api in haskell. noticed functions have tremendous number of arguments, e.g.
myapifunction :: key -> account -> int -> string -> int -> int -> io (mytype)
it's not bad, per se, have many arguments. user don't long argument functions. however, each of these args absolutely 100% necessary.
is there more haskell-ish way abstract on common parts of these functions? past account here used build url, need available, , stands depends entirely on function. things consistent though, key
, account
, , i'm wondering best abstract on these arguments is.
thank you!
you can combine these more descriptive data types:
data config = config { ckey :: key , caccount :: account }
then maybe have type
s or newtypes
make other arguments more descriptive:
-- have no idea these should be, i'm making 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
if config
needed, recommend working in reader
monad, can as
myapifunction :: (monadreader config io, monadio io) => count -> name -> position -> io mytype myapifunction count name (x, y) = conf <- ask liftio $ mypreviousapifunction (ckey conf) (caccount conf) name name x y
this uses mtl
library monad transformers. if don't want have type constraint on , over, can use constraintkinds
extension alias it:
{-# language constraintkinds #-} {-# language flexiblecontexts #-} ... type apictx io = (monadreader config io, monadio io) ... myapifunction :: apictx io => count -> location -> position -> io mytype myapifunction ...
depending on specific application, split multiple function. i've seen plenty of apis before had like
withcount :: apictx io => count -> io -> io withname :: apictx io => name -> io -> io withpos :: apictx io => position -> io -> io (&) :: -> (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)
these handful of techniques, there others out there start becoming more complex after this. others have different preferences on how this, , i'm sure plenty disagree me on whether of these practice (specifically constraintkinds
, isn't universally accepted).
if find having type signatures large lot, after applying of these techniques, maybe you're approaching problem wrong direction, maybe functions can broken down simpler intermediate steps, maybe of arguments can grouped logically more specific data types, maybe need larger record structure handle setting complex operations. it's pretty open ended right now.
Comments
Post a Comment