leontalbot
leontalbot

Reputation: 2543

Clojure: separating comp and partial arguments

Say I have a function that needs two arguments and where the order of arguments affects the results.

Is it possible to pass the first argument into a partial or comp function and the other aside of it, like this:

(defn bar [arg1 arg2] (- arg1 arg2))
(def baz (partial (bar arg1)))
(def qux (comp str (bar arg1)))

(baz arg2)
(qux arg2)

If I want to pass arg2 into the function, could I do something like this?

(def baz2 (partial (bar _ arg2)))
(def qux2 (comp str (bar _ arg2)))

(baz arg1)
(qux arg1)

Upvotes: 4

Views: 3575

Answers (3)

A. Webb
A. Webb

Reputation: 26446

Scheme SRFI 26 has a useful macro cut for slotting parameters like this.

Usage would be like so for your subtracting bar:

 ((cut bar <> 1) 2)
 ;=> 1
 ((comp str (cut - <> 1)) 2)
 ;=> "1"

Where the <> symbol represents the slot to be filled.

It is a fun exercise to implement a cut in Clojure yourself, but here is one port by @Baishampayan Ghose.

Upvotes: 4

S&#233;bastien RoccaSerra
S&#233;bastien RoccaSerra

Reputation: 17201

Here's what I got in a repl:

user=> (defn bar [arg1 arg2] (- arg1 arg2))
#'user/bar
user=> (def baz (partial bar 5))
#'user/baz
user=> (def qux (comp str baz))
#'user/qux
user=> (baz 2)
3
user=> (qux 2)
"3"

It's the closest I could get from your first example.

For the second example, maybe a simple defn is better than a partial def:

user=> (defn baz2 [x] (bar x 5))
#'user/baz2
user=> (def qux2 (comp str baz2))
#'user/qux2
user=> (baz2 2)
-3
user=> (qux2 2)
"-3"

I'd suggest you start a repl and try it yourself, it's the second best way to discover a language that I know of (TDD being the first).

Cheers!

Upvotes: 3

Francis Avila
Francis Avila

Reputation: 31621

partial only "fills in" arguments on the left side, so if you need to skip arguments you must use fn:

(def baz2 #(bar %1 arg2))

Note also that comp requires that all its arguments be functions, so your qux and qux2 are actually nonsense. They should be:

(def qux (comp str baz))
(def qux2 (comp str baz2))

In general, Clojure core functions will place the variable most likely to change last to make composition with comp and partial more natural. (E.g., the collection argument is almost always last in Clojure, except for things like into where it makes sense to put it first.) When you design your own functions you should stick to this convention so you can compose your functions more easily.

Upvotes: 9

Related Questions