[Haskell-cafe] Idiomatic Haskell equivalent of "keyword arguments"to functions

Brian Hulley brianh at metamilk.com
Fri Dec 29 23:39:23 EST 2006


Paul Moore wrote:
> I'm thinking around the design of a couple of things, and am hitting
> an issue which I know how I would solve in Python, but I'm not sure
> what a good idiomatic Haskell approach would be.
>
> The problem is that I am trying to write a function which takes a
> rather large number of arguments, many of which are optional (ie, have
> sensible defaults).

There's an interesting solution to this in section 15 (starting page 53) of 
Magnus Carlsson and Thomas Hallgren's Fudgets thesis available online at: 
http://www.cs.chalmers.se/~hallgren/Thesis/ (Fudgets main page is at 
http://www.cs.chalmers.se/ComputingScience/Research/Functional/Fudgets/ ).

Basically the idea is that for any function which takes lots of params, the 
params are gathered together into a datatype whose details are hidden from 
the user of the function. For each parameter, the user is given a function 
called a "Customiser" in the thesis, which takes a value of the hidden 
datatype and modifies it by setting the relevant parameter. Multiple params 
can therefore be specified by chaining Customisers together in any order 
with the usual function composition. The original function, instead of 
taking lots of params, now just takes a single parameter: a Customiser, 
which is used to turn the default params into the customised params.
This is similar to the idea of using records but has the advantage that by 
judicious use of typeclasses of which the param data is an instance, you 
don't need to keep on inventing different names for the same thing (eg to 
specify colour for the background of a label control in a GUI or colour for 
a font you could use the name "setColour" in both cases).
(A possible disadvantage is the overhead of having to create a whole new 
modified version of the parameter record for each Customiser in the 
composition so if efficiency were an issue you'd have to see if the compiler 
could inline the composition of the customiser functions to make it as 
efficient as the built in multiple field record update using rec{a=a', c=c'} 
syntax)

> To make things concrete, the example I'm really thinking of is a "send
> an email" function, which would take a subject, a body, a list of
> recipients, optional lists of cc and bcc recipients, an optional
> mailserver (default localhost), an optional port (default 25), and
> possibly optional authentication details. I found a couple of Haskell
> modules implementing a SMTP client, but they both just used a list of
> positional parameters, which I'm not really happy with. At the very
> least, I'd like to wrap them in a nicer interface for my code.


-- hidden from clients
data EmailParams =
    EmailParams
        { subject :: String
        , body :: String
        , recipients :: [Recipient]
        , cc :: [Recipient]
        , bcc :: [Recipient]
        , mailserver :: Mailserver
        , port :: Port
        , authentication :: Authentication
        }

-- record syntax elided to save space
defaultEmailParams = EmailParams "" "" [] [] [] defaultMailserver 
defaultPort defaultAuthentication

--a "Customiser" visible to clients
setSubject :: String -> EmailParams -> EmailParams
setSubject s ep = ep{subject = s}

-- etc

send :: (EmailParams -> EmailParams) -> IO ()
send f = sendInternal (f defaultEmailParams)
    where
        sendInternal :: EmailParams -> IO ()
        sendInternal = ...

-- In user code:

main = send (setSubject "Test" . setBody "A test email")

Brian.
-- 
http://www.metamilk.com 



More information about the Haskell-Cafe mailing list