Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/bsless/impedance
Fast declarative Clojure map transforms to solve impedance mismatch
https://github.com/bsless/impedance
clojure data-driven declarative performance transformations
Last synced: 3 months ago
JSON representation
Fast declarative Clojure map transforms to solve impedance mismatch
- Host: GitHub
- URL: https://github.com/bsless/impedance
- Owner: bsless
- License: other
- Created: 2020-10-17T14:08:36.000Z (over 4 years ago)
- Default Branch: master
- Last Pushed: 2020-12-10T15:57:56.000Z (about 4 years ago)
- Last Synced: 2024-10-13T10:26:44.806Z (3 months ago)
- Topics: clojure, data-driven, declarative, performance, transformations
- Language: Clojure
- Homepage:
- Size: 23.4 KB
- Stars: 55
- Watchers: 5
- Forks: 3
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
[![Clojars Project](https://img.shields.io/clojars/v/bsless/impedance.svg)](https://clojars.org/bsless/impedance)
[![cljdoc badge](https://cljdoc.org/badge/bsless/impedance)](https://cljdoc.org/d/bsless/impedance/CURRENT)
[![CircleCI](https://circleci.com/gh/bsless/impedance/tree/master.svg?style=shield)](https://circleci.com/gh/bsless/impedance/tree/master)# Impedance
Transform Clojure maps at speed.
## Rationale
In electronics, impedance mismatch is a case where an electrical load's
or source's impedance doesn't match that of the driver/sink system
(respectively). Impedance matching allows us to maximize the power
transfer across that boundary.A similar phenomenon happens in software, where in the boundary between
processes there is a mismatch between the representation model in one
and the other. This library, like a transformer in electronics, allows
us to easily transform an input map to look how our system would expect
and maximize the information flow.### Just maps
Maps are pervasive in Clojure for information modeling. While you can
cheat and access vectors associatively, the library does not yet support
mapping over sequences.## Why not Meander?
Meander is great. It's feature rich and beautiful. It is a whole
arsenal. On the other hand, Impedance is a simple hatchet. Good for one
thing, sharp enough, and simple. It's also faster.### Differences
- No scanning or Cartesian product. Only leaves can be matched.
### Performance differences
As tested with criterium:
```clojure
{:a {:b ?x :c ?y} "x" ?z} ;; from
{:x ?x :y ?y :z ?z} ;; to
;;; Bench transform default
;;; Execution time mean : 107.636019 ns
;;; Bench transform checked
;;; Execution time mean : 76.051257 ns
;;; Bench transform unchecked
;;; Execution time mean : 73.565921 ns
;;; Bench meander
;;; Execution time mean : 430.781144 ns
```## Usage
### Dependency
```clojure
[bsless/impedance "0.0.0-alpha1"]
```### A basic transformer
```clojure
(require '[impedance.transform :as t])
(def f (t/transform {:a {:b ?x :c ?y} "x" ?z} {:x (inc ?x) :y ?y :z ?z}))
(f {:a {:b 1 :c 2} "x" 3}) ;; => {:x 2, :y 2, :z 3}
```### Creating a transformer programmatically
Warning: uses `eval`. Use at your own risk.
```clojure
(def from {:a {:b ?x :c ?y} "x" ?z})
(def to {:x (inc ?x) :y ?y :z ?z})
(def f (t/eval-transform from to))
(f {:a {:b 1 :c 2} "x" 3}) ;; => {:x 2, :y 2, :z 3}
```### Inferred Context - Poor Man's jq
An alternate syntax for transformations is the inferred context one:
```clojure
(require '[impedance.context :as c])
(c/with-inferred-context ctx
{:a {:b (or ^:? [:foo :bar] ^:? [:fizz :buzz])
:c ^:? [:fizz :bazz]}
:x ^:? [:foo :quux]})
```Here, specify only the shape of the desired output, and use the `:?`
metadata on vectors to mark them as paths referring to the map `ctx`.This syntax can be used to create and define functions:
```clojure
(fntx :checked
{:a {:b (or ^:? [:foo :bar] ^:? [:fizz :buzz])
:c ^:? [:fizz :bazz]}
:x ^:? [:foo :quux]})
(defntx f :unchecked
{:a {:b (or ^:? [:foo :bar] ^:? [:fizz :buzz])
:c ^:? [:fizz :bazz]}
:x ^:? [:foo :quux]})
```### Context compiler modes
All context compilers and transformers receive an optional argument for mode, which can be one of the following:
- `:poly` - will use `clojure.core/get` to get values out of a collection. Highly polymorphic at the slight cost of performance.
- `:unchecked` - will use direct method invoke of `.valAt` on an object. Will throw if an object doesn't implement `ILookup` and NPE for `nil`.
- `:checked` - same as `:unchecked` but `nil` checks before every call to `.valAt`.## License
Copyright © 2020 Ben Sless
This program and the accompanying materials are made available under the
terms of the Eclipse Public License 2.0 which is available at
http://www.eclipse.org/legal/epl-2.0.This Source Code may also be made available under the following Secondary
Licenses when the conditions for such availability set forth in the Eclipse
Public License, v. 2.0 are satisfied: GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or (at your
option) any later version, with the GNU Classpath Exception which is available
at https://www.gnu.org/software/classpath/license.html.