Best practices for named arguments

2012-06-15 Thread David Jacobs
TL;DR: I want to know best practices for designing functions with multiple 
optional arguments.

Okay, so I'm working to build machine learning algorithms in Clojure, and 
they tend to need many arguments. Being a long-time Ruby dev, I like to 
provide sensible defaults for almost all potential arguments that the 
functions take. However, there are some parameters that have to be explicit 
(namely, the data).

To alleviate the pain here, I've started to experiment with named 
arguments. So far, I've come up with something like the following:

(defn descend [xs ys  args]
  (let [defaults {:gradient-fn gradient
  :cost-fn cost
  :yield-fn println
  :alpha 0.01
  :iterations 1000
  :thetas (matrix 0 (second (dim xs)) 1)}
options (merge defaults (apply hash-map args))
{:keys [gradient-fn cost-fn yield-fn thetas alpha iterations]} 
options]
(do-the-algorithm-using-locally-bound-vars)))

It's a little wordy and could be extracted into a macro a la defnk (RIP 
clojure.contrib.def), but it works.

However, if I then want to use method delegation for some algorithms, the 
named argument endeavor gets trickier.

Say I have the same function in two namespaces. One is a general gradient 
descent function, and the other is a specific gradient descent function 
whose only role is to curry a named parameter into the general function.

I want to do something like the following:

(defn descend [xs ys  args]
  (optimization/descend xs ys (conj args :cost-fn cost)))

The problem, of course, is that if I want to delegate the args array to 
another function, I have to destructure args first before passing it into 
another function. In fact, if I ever have a delegating function like this 
(where a partial apply isn't good enough), I can't pass args through to the 
delegating function because it's automatically vectorized.

How do I splat vectors into parameter lists? (Should I be passing in 
records/maps instead of named parameters?)

Thanks,
David

-- 
You received this message because you are subscribed to the Google
Groups Clojure group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en

Re: Best practices for named arguments

2012-06-15 Thread Vinzent


 TL;DR: I want to know best practices for designing functions with multiple 
 optional arguments.


Use destructing:

(defn f [required  {:keys [foo bar] :or {foo :default}}]
  [required foo bar])

(f 3 :bar 1 :foo 2) ;= [3 2 1]
(f 3 :bar 1)  ;= [3 :default 1]

-- 
You received this message because you are subscribed to the Google
Groups Clojure group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en

Re: Best practices for named arguments

2012-06-15 Thread Meikel Brandmeyer (kotarak)
Hi,

you can use destructuring to provide defaults. And you can easily curry in 
options when passing things through.

(defn general-descend
  [xy ys 
   {:keys [gradient-fn cost-fn yield-fn alpha iterations thetas]
:or   {cost-fncost
   yield-fn   println
   alpha  0.01
   iterations 1000
   thetas (matrix 0 (second (dim xs)) 1)}}]
  ...)

(defn special-descend
  [xs ys  options]
  (apply general-descend xs ys :cost-fn cost options))

Kind regards
Meikel

-- 
You received this message because you are subscribed to the Google
Groups Clojure group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en

Re: Best practices for named arguments

2012-06-15 Thread David Jacobs
I'm not sure you read the whole question. I want to know how to delegate 
optional arguments to other functions with the same method signatures.

On Friday, June 15, 2012 12:04:00 AM UTC-7, Vinzent wrote:

 TL;DR: I want to know best practices for designing functions with multiple 
 optional arguments.


 Use destructing:

 (defn f [required  {:keys [foo bar] :or {foo :default}}]
   [required foo bar])

 (f 3 :bar 1 :foo 2) ;= [3 2 1]
 (f 3 :bar 1)  ;= [3 :default 1]


-- 
You received this message because you are subscribed to the Google
Groups Clojure group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en

Re: Best practices for named arguments

2012-06-15 Thread David Jacobs
Ah I see, I didn't realize I could apply the general-descend algorithm to 
both atoms and arrays to get a flattened list. Thanks!

On Friday, June 15, 2012 12:05:36 AM UTC-7, Meikel Brandmeyer (kotarak) 
wrote:

 Hi,

 you can use destructuring to provide defaults. And you can easily curry in 
 options when passing things through.

 (defn general-descend
   [xy ys 
{:keys [gradient-fn cost-fn yield-fn alpha iterations thetas]
 :or   {cost-fncost
yield-fn   println
alpha  0.01
iterations 1000
thetas (matrix 0 (second (dim xs)) 1)}}]
   ...)

 (defn special-descend
   [xs ys  options]
   (apply general-descend xs ys :cost-fn cost options))

 Kind regards
 Meikel



-- 
You received this message because you are subscribed to the Google
Groups Clojure group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en

Re: Best practices for named arguments

2012-06-15 Thread Marcus Lindner
I think the best is to use maps. It is rarly a good idea to have too many
arguments.
Am 15.06.2012 08:51 schrieb David Jacobs da...@wit.io:

 TL;DR: I want to know best practices for designing functions with multiple
 optional arguments.

 Okay, so I'm working to build machine learning algorithms in Clojure, and
 they tend to need many arguments. Being a long-time Ruby dev, I like to
 provide sensible defaults for almost all potential arguments that the
 functions take. However, there are some parameters that have to be explicit
 (namely, the data).

 To alleviate the pain here, I've started to experiment with named
 arguments. So far, I've come up with something like the following:

 (defn descend [xs ys  args]
   (let [defaults {:gradient-fn gradient
   :cost-fn cost
   :yield-fn println
   :alpha 0.01
   :iterations 1000
   :thetas (matrix 0 (second (dim xs)) 1)}
 options (merge defaults (apply hash-map args))
 {:keys [gradient-fn cost-fn yield-fn thetas alpha iterations]}
 options]
 (do-the-algorithm-using-locally-bound-vars)))

 It's a little wordy and could be extracted into a macro a la defnk (RIP
 clojure.contrib.def), but it works.

 However, if I then want to use method delegation for some algorithms, the
 named argument endeavor gets trickier.

 Say I have the same function in two namespaces. One is a general gradient
 descent function, and the other is a specific gradient descent function
 whose only role is to curry a named parameter into the general function.

 I want to do something like the following:

 (defn descend [xs ys  args]
   (optimization/descend xs ys (conj args :cost-fn cost)))

 The problem, of course, is that if I want to delegate the args array to
 another function, I have to destructure args first before passing it into
 another function. In fact, if I ever have a delegating function like this
 (where a partial apply isn't good enough), I can't pass args through to the
 delegating function because it's automatically vectorized.

 How do I splat vectors into parameter lists? (Should I be passing in
 records/maps instead of named parameters?)

 Thanks,
 David

 --
 You received this message because you are subscribed to the Google
 Groups Clojure group.
 To post to this group, send email to clojure@googlegroups.com
 Note that posts from new members are moderated - please be patient with
 your first post.
 To unsubscribe from this group, send email to
 clojure+unsubscr...@googlegroups.com
 For more options, visit this group at
 http://groups.google.com/group/clojure?hl=en

-- 
You received this message because you are subscribed to the Google
Groups Clojure group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en

Re: Best practices for named arguments

2012-06-15 Thread Gunnar Völkel
Hello David.
I have a very similar scenario according to named parameters liker you.
Therefore I have written the library clojure.options which can be found 
here:
https://github.com/guv/clojure.options

The latest version is also on clojars.

Greetings,
Gunnar

-- 
You received this message because you are subscribed to the Google
Groups Clojure group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en

Re: Best practices for named arguments

2012-06-15 Thread David Jacobs
Very cool, this is exactly what I wanted. Thanks.

On Friday, June 15, 2012 7:27:05 AM UTC-7, Gunnar Völkel wrote:

 Hello David.
 I have a very similar scenario according to named parameters liker you.
 Therefore I have written the library clojure.options which can be found 
 here:
 https://github.com/guv/clojure.options

 The latest version is also on clojars.

 Greetings,
 Gunnar


-- 
You received this message because you are subscribed to the Google
Groups Clojure group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en