scicloj / clojisr

Clojure speaks statistics - a bridge between Clojure to R
https://scicloj.github.io/clojisr/
Eclipse Public License 2.0
147 stars 9 forks source link

R functions arglist #22

Open genmeblog opened 4 years ago

genmeblog commented 4 years ago

I prepared POC for adding arglist for RObjects acting as function using formals. It can be helpful for REPL driven development. Arglists conform calling way in clojuress (associative destructuring on variadic position)

Examples:

(formals base/mean)
;; => ([x & {:keys [...]}])
(formals stats/arima0) 
;; => ([x & {:keys [order seasonal xreg include.mean delta transform.pars fixed init method n.cond optim.control]}])
(formals dev/dev-off)
;; => ([& {:keys [which]}])
(formals base/Sys-info)
;; => ([])

formals can be used to create :arglists meta tag.

(I checked and it works on CIDER)

daslu commented 4 years ago

Nice.

This is related to #8 .

genmeblog commented 4 years ago

Just to leave it before pull request. Formals is defined as below:

(def ^:private empty-symbol (symbol ""))

(defn formals
  [{:keys [code class]}]
  (when (= class ["function"])
    (let [args (-> (format "formals(%s)" code)
                   r
                   r->clj)
          {:keys [obl opt]} (reduce (fn [m [k v]]
                                      (let [selector (if (and (= empty-symbol v)
                                                              (not (seq (:obl m)))) :obl :opt)]
                                        (update m selector conj (symbol k))))
                                    {:obl [] :opt []}
                                    args)]
      (cond
        (and (seq obl)
             (seq opt)) (list (conj obl '& {:keys opt}))
        (seq obl) (list obl)
        (seq opt) (list ['& {:keys opt}])
        :else '([])))))

(alter-meta! #'stats/arima0 assoc :arglists (formals stats/arima0))

(meta #'stats/arima0)
;; => {:asdf 12, :name arima0, :ns #namespace[stats], :arglists ([x & {:keys [order seasonal xreg include.mean delta transform.pars fixed init method n.cond optim.control]}])}

Adding metadata can be done during intern in require-r.

genmeblog commented 4 years ago

Sorry for duplicate.

daslu commented 4 years ago

Hi @genmeblog .

  1. This is great!

  2. Added some regression tests for the functions you mentioned: https://github.com/scicloj/clojisr/commit/aecefd3061720079aed7fda1d7bb4137e8fef17f

  3. Added support for primitive functions: https://github.com/scicloj/clojisr/commit/ef312b7306933ca75ca4888e4ab89b4cbd9a4613

  4. Thinking about it, maybe the handling of arglists could be done not only when doing require-r, but rather, every time we create an RObject. This way, when we create an R function with (r 'sum) or (r '[function [x y] (+ x y)]), we get the arglists too. What do you think? If this sounds good, I can do it tomorrow.

(edit: typo)

genmeblog commented 4 years ago

Great! Regarding 4: this would be the best solution. But remember that meta are attached to symbol not to object itself.

genmeblog commented 2 months ago

should we close this?