4 Kindly-advice
ns kindly-advice
(:require [scicloj.kindly-advice.v1.api :as kindly-advice]
(:as kind]
[scicloj.kindly.v4.kind :as kindly])) [scicloj.kindly.v4.api
Kindly-advice is a small library to advise Clojure data visualization and notebook tools how to display forms and values, following the Kindly convention.
4.1 Status
Kindly-advice will stabilize soon and is currently getting feedback from tool-makers.
4.2 Goal
provide tools with the necessary information to support Kindly
have sensible defaults
be user-extensible
4.3 Asking for advice
-> {:value (kind/hiccup
(:div [:h1 "hello"]])}
[
kindly-advice/advise kind/pprint)
:value [:div [:h1 "hello"]],
{:meta-kind :kind/hiccup,
:kindly/options {},
:kind :kind/hiccup,
:advice
:kind/hiccup]
[[:kind/hiccup {:reason :metadata}]
[:kind/vector {:reason :predicate}]
[:kind/seq {:reason :predicate}]]} [
The :kind
field is the important one, expressing the bottom line of the inference: Kindly-advice recommends the tool handles this value as Hiccup.
The tool’s job will usually be to display the :value
field based on the :kind
field.
In the following example, we are asking for advice for given form (annotated by Kindly in this example). Kindly-advice evaluates the form and adds the resulting value to complete the context. This completion will only take place if the value is missing. It is recommended that tools will take care of evaluation themselves and pass the complete context to Kindly-advice. Doing so allows the tool to handle Exceptions better, among other things. Kindly-advice checks both the form and value for metadata. The metadata might not be present on the value.
-> {:form ^:kind/hiccup
(:div [:h1 "hello"]]}
[
kindly-advice/advise kind/pprint)
:form [:div [:h1 "hello"]],
{:value [:div [:h1 "hello"]],
:meta-kind :kind/hiccup,
:kindly/options {},
:kind :kind/hiccup,
:advice
:kind/hiccup]
[[:kind/hiccup {:reason :metadata}]
[:kind/vector {:reason :predicate}]
[:kind/seq {:reason :predicate}]]} [
Sometimes, there is no inferred kind, as no metadata or relevant predicates say anything useful:
-> {:form '(+ 1 2)}
(
kindly-advice/advise kind/pprint)
:form (+ 1 2),
{:value 3,
:meta-kind nil,
:kindly/options {},
:advice []}
In some situations, the kind inferred by predicates. Kindly-advice has a list of default predicates, which can be extended by the user. In the following example, it recognizes a dataset created by Tablecloth.
require '[tablecloth.api :as tc]) (
-> {:value (tc/dataset {:x (range 4)})}
(
kindly-advice/advise kind/pprint)
:value _unnamed [4 1]:
{
:x |
|
|---:|0 |
| 1 |
| 2 |
| 3 |
|
,:meta-kind nil,
:kindly/options {},
:kind :kind/dataset,
:advice
:kind/dataset {:reason :predicate}]
[[:kind/map {:reason :predicate}]]} [
4.4 Examples
Kindly-advice is used by the following projects:
For tool makers looking to support Kindly, the kind-portal
implementation is a good example to start from.
4.5 Extending
One my extend kindly-advice to perform custom kind inference.
In the following example, we add our own advisor, which recognizes vectors beginning with a :div
keyword as :kind/hiccup
.
def my-advisor
(fn [{:keys [value]}]
(if (and (vector? value)
(-> value first (= :div)))
(:kind/hiccup]]))) [[
(kindly-advice/set-advisors!cons #'my-advisor
( kindly-advice/default-advisors))
#'kindly-advice/my-advisor
(
#function[scicloj.kindly-advice.v1.advisors/meta-kind-advisor]15854]) #function[scicloj.kindly-advice.v1.advisors/predicate-based-advisor/fn--
-> {:form '[:div [:p "hello"]]}
(
kindly-advice/advise kind/pprint)
:form [:div [:p "hello"]],
{:value [:div [:p "hello"]],
:meta-kind nil,
:kindly/options {},
:kind :kind/hiccup,
:advice
:kind/hiccup]
[[:kind/vector {:reason :predicate}]
[:kind/seq {:reason :predicate}]]} [
source: notebooks/kindly_advice.clj