Defining partial functions with reduced arity

It was sometimes convenient for me to use Clojure to define abridged versions of functions that return a partial function, for example

(defn prefix ([pre string] (str pre ":" string)) ([pre] (fn [string] (prefix pre string)))) 

This means you can do this:

 (prefix "foo" 78979) => "foo:78979" ((prefix "foo") 78979) => "foo:78979" 

This seems pretty Haskell-ish and avoids the need for partial to create partial functions.

But is this considered a good coding style / API design in Lisp?

+8
functional-programming lisp clojure
source share
3 answers

In languages ​​where functions are defined by default, function calls are also displayed. When someone writes (fabc) , the language interprets this as (((fa) b) c) . This does not apply to Clojure.

I believe that creating curry functions in an environment where calls were not made by default creates a conceptual inconsistency - this construction is likely to cause confusion among readers (I mean readers of your code).

If your function has more than two arguments, the definition becomes ugly fast. Suppose a function has 4 arguments. To fully emulate a currying call, you need to handle cases like ((fab) cd) , when someone passes 2 arguments first and then the other two. In this case, an overloaded version of a function with two arguments should return an overloaded function that behaves differently depending on whether it receives 1 or 2 arguments. I suppose you can automate this with macros, but still.

In addition, you miss the opportunity to define default arguments and the & rest construct.

+7
source share

Using partial to create a curried function is based on the concept of Explicitly Better (in most cases :)). And I found that this concept is more applicable / used in dynamically typed languages ​​such as Clojure, Python, etc., Maybe due to the lack of a type / static input signature, it makes sense to make things explicit.

+9
source share

hmmm ... personally, I’d better look at partial , as this makes it clear what is happening.

I don’t know if it was a “good” or “bad” coding style, but I had never seen this style in the existing Clojure code, and I can imagine that people using the API would expect like (prefix "foo" 78979) and (prefix "foo") to return the same type of object.

To make the difference between both functions, you can do something like this:

 (defn prefix [pre string] (str pre ":" string)) (defn prefix-fn [pre] (fn [string] (prefix pre string))) (prefix "foo" 78979) ; => "foo:78979" ((prefix-fn "foo") 78979) ; => "foo:78979" 
+6
source share

All Articles