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

2006-12-29 Thread Brian Hulley

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 


___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


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

2006-12-29 Thread Paul Moore

On 12/29/06, Neil Mitchell <[EMAIL PROTECTED]> wrote:

Records are your friend.

[...]

The other alternative is:

data EmailParams = Body String
| Port Int
| Mailserver String


Neat ideas. Thanks. I guess there could there be disadvantages
involved in using a list of arguments, rather than a curried function
(can't easily do partial application, for example) - but I don't know
if these would be a big deal in any practical program.

As I mentioned, I'm interested in trying to expand my brain, as well
as just solve a particular problem :-)

Thanks for the ideas - I'll ponder on them.

On 12/29/06, David House <[EMAIL PROTECTED]> wrote:

On 29/12/06, Paul Moore <[EMAIL PROTECTED]> wrote:
> I looked at wxHaskell for inspiration



This is actually a really nice solution, if you think about it:

[...]

Oh, in principle I agree (your 3 reasons are exactly why I like
keyword parameters in Python). I'm not particularly sure if it's a bit
over-complex for the sorts of things I have in mind, but it certainly
looks nice in wxHaskell.


Try again to understand the typing, hopefully you'll see this is
probably The Best Way. If you have any questions about the typing
itself, just post them here.


I'm sure I can follow the typing with a bit of thinking, and it should
be educational to work it through.

Thanks to both of you for some useful ideas.

Paul.
___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


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

2006-12-29 Thread David House

On 29/12/06, Paul Moore <[EMAIL PROTECTED]> wrote:

I looked at wxHaskell for inspiration - its approach (button f [text
:= "Quit", on command := close f]) looks quite readable, but slightly
unusual (to me) for Haskell. It also seems fairly complex to implement
(ie, my head hurt when I tried to follow the types involved, but maybe
that's just because it's getting late :-))


I forgot one - it's extensible, so if you want to add extra parameters
you don't need to change the type of the function, and you don't need
to change every single call site either.

--
-David House, [EMAIL PROTECTED]
___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


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

2006-12-29 Thread David House

On 29/12/06, Paul Moore <[EMAIL PROTECTED]> wrote:

I looked at wxHaskell for inspiration - its approach (button f [text
:= "Quit", on command := close f]) looks quite readable, but slightly
unusual (to me) for Haskell. It also seems fairly complex to implement
(ie, my head hurt when I tried to follow the types involved, but maybe
that's just because it's getting late :-))


This is actually a really nice solution, if you think about it:

1) You don't have to memorise the order the parameters come in (you
can put the parameters in any order in that list).
2) It's self-documenting, f arg1 arg2 arg3 doesn't say what arg1, arg2
and arg3 do, but this way you get an idea.
3) If you had a function in another language with 10 parameters, all
of which are optional, but you want to specify the last one, you have
to include the default values (which may involve looking up what they
are) of the first 9; no such problems here.

Try again to understand the typing, hopefully you'll see this is
probably The Best Way. If you have any questions about the typing
itself, just post them here.

--
-David House, [EMAIL PROTECTED]
___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


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

2006-12-29 Thread Neil Mitchell

Hi Paul,


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.


Records are your friend.

data Email = Email {subject :: String, body :: String, to ::
[Address], cc = [Address], bcc = [Address], mailserver :: String, port
:: Int}

defaultEmail = Email{subject = "No subject", body = "", to = [], cc =
[], bcc = [], mailserver = "localhost", port = 25}

The user can then go:

sendEmail defaultEmail{subject="Subject here", body = "body here", to
= ["haskell-cafe"], mailserver = "server.haskell.org"}

Now things which are't specified (port) keep their default value.

The other alternative is:

data EmailParams = Body String
   | Port Int
   | Mailserver String
 ...

then:

sendEmail [Body "body here", To "haskell-cafe", Mailserver
"server.haskell.org" ...]

I prefer the first, but the second can also be done.

Thanks

Neil
___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


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

2006-12-29 Thread Paul Moore

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). The canonical example of this is creating a GUI
window, which involves a lot of style options, most of which would
typically be left to default. In Python, this type of interface is
often handled either as a function with many keyword arguments, or as
a mutable object which has attributes set, and then a method called to
handle the function call. Neither of these approaches seems plausible
in Haskell.

I looked at wxHaskell for inspiration - its approach (button f [text
:= "Quit", on command := close f]) looks quite readable, but slightly
unusual (to me) for Haskell. It also seems fairly complex to implement
(ie, my head hurt when I tried to follow the types involved, but maybe
that's just because it's getting late :-))

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.

I'd appreciate any ideas about how to think of this sort of problem -
I'm pretty sure that what I need to do is think differently about the
issue, rather than just mechanically translating the code I'd write in
Python. But I don't really know how. Any pointers would be very
helpful!

Thanks,
Paul.
___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe