hara.function reasoning about functions

Author: Chris Zheng  (z@caudate.me)
Date: 11 February 2018
Repository: https://github.com/zcaudate/hara
Version: 2.8.2

hara.function allow reasoning and dispatch of functions.

1    function.args

Add to project.clj dependencies:

[zcaudate/hara.function.args "2.8.2"]

hara.function.args allow reasoning on the arguments of clojure methods

arg-check ^

counts the number of non-varidic argument types

v 2.1
(defn arg-check
  [f num]
  (or (if-let [vc (varg-count f)]
        (<= vc num))
      (some #(= num %) (arg-count f))
      (throw (Exception. (str "Function must accomodate " num " arguments")))))
(arg-check (fn [x]) 1) => true (arg-check (fn [x & xs]) 1) => true (arg-check (fn [x & xs]) 0) => (throws Exception "Function must accomodate 0 arguments")

arg-count ^

counts the number of non-varidic argument types

v 2.1
(defn arg-count
  (let [ms (filter (fn [^java.lang.reflect.Method mthd]
                     (= "invoke" (.getName mthd)))
                   (.getDeclaredMethods (class f)))
        ps (map (fn [^java.lang.reflect.Method m]
                  (.getParameterTypes m)) ms)]
    (map alength ps)))
(arg-count (fn [x])) => [1] (arg-count (fn [x & xs])) => [] (arg-count (fn ([x]) ([x y]))) => [1 2]

op ^

loose version of apply. Will adjust the arguments to put into a function

v 2.1
(defn op
  [f & args]
  (let [nargs (count args)
        vargs (varg-count f)]
    (if (and vargs (>= nargs vargs))
      (apply f args)
      (let [fargs (arg-count f)
            candidates (filter #(<= % nargs) fargs)]
        (if (empty? candidates)
          (throw (Exception. (str "arguments have to be of at least length " (apply min fargs))))
          (let [cnt (apply max candidates)]
            (apply f (take cnt args))))))))
(op + 1 2 3 4 5 6) => 21 (op (fn [x] x) 1 2 3) => 1 (op (fn [_ y] y) 1 2 3) => 2 (op (fn [_] nil)) => (throws Exception)

varg-count ^

counts the number of arguments types before variable arguments

v 2.1
(defn varg-count
  (if (some (fn [^java.lang.reflect.Method mthd]
              (= "getRequiredArity" (.getName mthd)))
            (.getDeclaredMethods (class f)))
    (.getRequiredArity ^clojure.lang.RestFn f)))
(varg-count (fn [x y & xs])) => 2 (varg-count (fn [x])) => nil

vargs? ^

checks that function contain variable arguments

v 2.1
(defn vargs?
  [^clojure.lang.Fn f]
  (if (some (fn [^java.lang.reflect.Method mthd]
              (= "getRequiredArity" (.getName mthd)))
            (.getDeclaredMethods (class f)))
(vargs? (fn [x])) => false (vargs? (fn [x & xs])) => true

2    function.dispatch

Add to project.clj dependencies:

[zcaudate/hara.function.dispatch "2.8.2"]

hara.function.dispatch allows alternative ways of calling a function

call ^

executes `(f v1 ... vn)` if `f` is not nil

v 2.1
(defn call
  ([f] (if-not (nil? f) (f)) )
  ([f v] (if-not (nil? f) (f v)))
  ([f v1 v2] (if-not (nil? f) (f v1 v2)))
  ([f v1 v2 v3] (if-not (nil? f) (f v1 v2 v3)))
  ([f v1 v2 v3 v4 ] (if-not (nil? f) (f v1 v2 v3 v4)))
  ([f v1 v2 v3 v4 & vs] (if-not (nil? f) (apply f v1 v2 v3 v4 vs))))
(call nil 1 2 3) => nil (call + 1 2 3) => 6

msg ^

message dispatch for object orientated type calling convention.

v 2.1
(defn msg
  ([obj kw] (call (obj kw) obj))
  ([obj kw v] (call (obj kw) obj v))
  ([obj kw v1 v2] (call (obj kw) obj v1 v2))
  ([obj kw v1 v2 v3] (call (obj kw) obj v1 v2 v3))
  ([obj kw v1 v2 v3 v4] (call (obj kw) obj v1 v2 v3 v4))
  ([obj kw v1 v2 v3 v4 & vs] (apply call (obj kw) obj v1 v2 v3 v4 vs)))
(def obj {:a 10 :b 20 :get-sum (fn [this] (+ (:b this) (:a this)))}) (msg obj :get-sum) => 30