Composition of a branching function: compositional version of if / cond?

Clojure has several options for composing functions. There are composition functions for:

  • Apply: for expand arguments
  • Partial: for arguments not yet set
  • Comp: for consistent connection results through several functions
  • Juxt: to apply one argument to multiple functions

However, AFAIK does not exist such composite functions that include branching. Are there any functions that make up functions in branches, like a functional version of if or cond ?

Of course, if the version is easy to make (although this implementation may not be the fastest):

 (defn iff ([pred rtrue] (iff pred rtrue identity)) ([pred rtrue rfalse] (fn [& args] (if (apply pred args) (apply rtrue args) (apply rfalse args))))) 

In this case, the question of returning by default in case of "else" by the rule, or if in this case it is necessary to return nil, can be discussed.

Using such a function can lead to easier code reading. Instead of #(if (string? %) (trim %) %) it will become (iff string? trim) or with cond version:

 (condf string? trim, vector? (partial apply str), :else identity) 

Do other FP languages โ€‹โ€‹have such constructs? I can imagine that this can be convenient in compositions with comp and juxt. Why not Clojure?

Bonus points for realistic implementations iff / condf :)

+4
source share
3 answers

Well, there may be many such composition patterns that you can find and ask why this is not in the main language. The reason is obvious, it is impossible. The core of the language provides you with all the constructs for building such patterns. Such functions relate more to contrib , and not to the core language.

As for the implementation, it will be as simple as shown below:

 (defn condf [& args] (let [chain (partition 2 args)] (fn [& params] (first (for [[pf] chain :when (or (= :else p) (apply p params))] (apply f params)))))) (def my-func (condf string? clojure.string/trim vector? (partial apply str) :else identity)) (my-func "Ankur ") ==> "Ankur" (my-func [1 2 3]) ==> "123" (my-func '(1 2 3)) ==> (1 2 3) 
+1
source

I'm not sure if this is a direct match with what you are looking for (the question, for me, is somewhat vague), but you should look in Monads and Arrows.

Monads allow you to combine functions with a special "binding" function, which determines how to connect them. He could do some pipeline processing if / else, for example, in Maybe Modifications and Either, or simulate a state, like in a state monad.

Monads are built into Haskell (like monads) and F # (like "Workflows"). I saw monad libraries for Clojure ( check this out for one ), and there are probably libraries with arrows.

+2
source

This is approaching the idea of โ€‹โ€‹strategic programming. You can find the following paper of interest

The essence of strategic programming Ralph Lemmel and Eelko Visser and Jost Visser

http://homepages.cwi.nl/~ralf/eosp/

http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.20.1969

+1
source

Source: https://habr.com/ru/post/1444406/


All Articles