Git Product home page Git Product logo

medley's Introduction

Medley Build Status

Medley is a lightweight Clojure/ClojureScript library of useful, mostly pure functions that are "missing" from clojure.core.

Medley has a tighter focus than flatland/useful or Plumbing, and limits itself to a small set of general-purpose functions.

Installation

Add the following dependency to your deps.edn file:

dev.weavejester/medley {:mvn/version "1.8.0"}

Or to your Leiningen project file:

[dev.weavejester/medley "1.8.0"]

Documentation

Ports

Pre-1.0 Breaking Changes

In 0.7.0 the minimum Clojure version was changed from 1.5.1 to 1.7.0 to take advantage of reader conditionals. The update function has also been removed, as it is now present in clojure.core.

In 0.6.0 the type signature of greatest and least was changed to be more like max and min in Clojure core. If you're upgrading from a version prior to 0.6.0, please update your usage of greatest and least.

License

Copyright © 2023 James Reeves

Distributed under the Eclipse Public License either version 1.0 or (at your option) any later version.

medley's People

Contributors

anthonygalea avatar borkdude avatar darkleaf avatar dmcgillen avatar eraserhd avatar henrygarner avatar madstap avatar mbutlerw avatar stevejmp avatar tobereplaced avatar tomdl89 avatar transducer avatar weavejester avatar yuhan0 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

medley's Issues

Transducer versions for functions over collections

Would it be interesting to provide transducer variants for the medley functions that runs over collections? distinct-by, take-upto, drop-upto, indexed and probably some others do have transducer variants which could be useful.

Suggestion: template

I sometimes find myself needing to template EDN literals in code where clojure.template/do-template is too limited (e.g. it doesn't resolve locals) and syntax-quote does too much (it auto-qualifies symbols.

So I wrote this function:

(defn template [expr replacement-map]
  (walk/postwalk
   (fn [expr]
     (if-let [[_ v] (find replacement-map expr)]
       v expr)) expr))

(template '{:linters {:unresolved-symbol {:exclude [::foo y z]}}} '{::foo x})
;;=> {:linters {:unresolved-symbol {:exclude [x y z]}}}

Perhaps there are more people who regularly need this templating function. It's too small to live in a library but perhaps it would be good to have this in medley.

add a new function `dates` ?

Hello, Mr Reeves.

Great repository here ! since in Clojure.core we have function doubles to initiate a double array from a collection. Do you think whether it is a good idea to include a dates in medley ?

basically it can be written as

(defn dates [ x ]
    (into-array LocalDate x )) 

map-vals loses meta-data of containing collection [0.7.1]

I've found that if I have a collection, a map with meta data, and execute medley/map-vals upon it, the resulting map does not have the meta-data.

(require '[medley.core :as medley])
=> nil
(def x (with-meta {:my-meta 1} {:foo 1}))
=> #'user/x
(-> (medley/map-vals inc x) meta)
=> nil
(meta x)
=> {:foo 1}

Suggested addition: index-of

The humble indexOf -> you have a known small vector or sequence, you are doing ops on it and you want to find a particular element's index. (Because you have to e.g. replace it later, or put something before or after it).

Naive implementation:

(defn index-of
  "Return the first index of x inside a seq of xs, or nil"
  [xs x]
  (->> xs
       (medley/indexed)
       (medley/find-first (fn [[_idx item]]
                            (= item x)))
       (first)))

Interactive docs

Hi James,

medley is self-host cljs compatible. It runs fine on klipse.

Would you like to have an interactive version of the documentation with the klipse codox theme?

Minor Clojure 1.11 Alpha 4 compatibility issue

Alpha 4 introduces a new abs function in clojure.core leading to this warning:

WARNING: abs already refers to: #'clojure.core/abs in namespace: medley.core, being replaced by: #'medley.core/abs

Variadic version of map-vals

Would it be a good idea for map-vals to accept multiple collections with a variadic function, just like regular map and mapcat?

(map-vals min
  {:x 1 :y 4 :z 20}
  {:x 3 :y -6 :z 15}
  {:x 0 :y 8 :z 16})
;; => {:x 0, :y -6, :z 15}

(map-vals concat
  {:xs [1 2 3] :ys [4 5 6]}
  {:xs [3 2 1] :ys [7 8 9]})
;; => {:xs (1 2 3 3 2 1), :ys (4 5 6 7 8 9)}

It would break symmetry with map-keys and map-kv, which don't seem to have an intuitive analogue for being applied to multiple colls.

Also I'm not sure how missing or extra keys should be handled:

(map-vals + {:foo 10} {:foo 5 :bar 6})
;; => {:foo 15 :bar ??}

Release request, to prevent warnings for Clojure 1.11 users

Requesting a new release be pushed.

Due to #59 , warnings are output when running projects, starting REPL's, and reloading deps for Clojure 1.11 users. Since the issue was resolved in #60, pushing a new release would prevent these warnings.

If there's anything I can do to help, please let me know. Thanks!

`time` as data?

Hey James,

one fairly usual need I have in Clojure projects is to time things, and obtain the timing result as data.

Wrapping clojure.core/time in a with-out-str can have unintended effects and needs parsing anyway.

So a time in medley that returned [computation, timing] might not look out of place.

Cheers - V

Warning when using in Clojure 1.7

When using Medley in Clojure 1.7 you get the following warning:

WARNING: update already refers to: #'clojure.core/update in namespace: medley.core, being replaced by: #'medley.core/update

split-when

Hey @weavejester, I sometimes find myself in the need of this:

(defn split-when
  [pred coll]
  (lazy-seq
   (when-let [s (seq coll)]
     (let [fst (first s)
           f (complement pred)
           run (cons fst (take-while #(f %) (next s)))]
       (cons run (split-when pred (lazy-seq (drop (count run) s))))))))

Could add a transducer arity-1 to it if this feels useful.

Example:

(split-when symbol? ['foo 1 2 3 'bar 5 6]) ;;=> ((foo 1 2 3) (bar 5 6))

Suggested addition: generalization of group-by/index-by

Not infrequently I find myself wanting to to group a collection with a custom collation. Between medley and clojure.core we already have two functions with hard-coded collations: group-by uses conj on a vector, and index-by uses last-wins collation. Both functions could be implemented in terms of a more general one that also lets devs provide their own collations:

;; Placeholder name, this could even be additional arities of index-by
;; Naive implementation, not optimized
(defn group-with
  "key fn, collating fn, initial value, coll"
  ([kf cf coll]
   (reduce #(let [k (kf %2)]
              (assoc %1 k (if-some [v (get %1 k)] 
                            (cf v %2)
                            %2)))
           {} coll))
  ([kf cf init coll]
   (reduce #(update %1 (kf %2) (fnil cf init) %2) {} coll)))

Here are some usage examples that compare implementations with and without this function:

(def data
  ["apple" "banana" "clojure" "aardvark"])

;; Implementing group-by in terms of group-with
(group-by first data)
(group-with first conj [] data)

;; What if you want to use a different collection type?
(reduce #(update %1 (first %2) (fnil conj #{}) %2) {} data)
(-> (group-by first data) (update-vals set))  ;more clear, but inefficient

(group-with first conj #{} data)


;; First, defining a helper. This might also be a useful addition to medley, I'll file a separate issue if you're interested
(defn unapply
 "The opposite of apply: (unapply f [a b] c d) -> (f a b [c d])"
 [f & args]
  (if (and (vector? (first args)) (seq (rest args)))
    ((apply partial f (first args)) (rest args))
    (f args)))


;; Implementing index-by in terms of group-with
(into {} (map (juxt first identity)) data)
(-> (group-by first data) (update-vals last))  ;more clear, but inefficient
(reduce #(assoc %1 (first %2) %2) {} data)
(m/index-by first data)  ;obviously index-by is the most concise

(group-with first (fn [_ b] b) data)
(group-with first (partial unapply second) data)  ;unapply helps this read a little more clearly


;; What if you want first-wins collation instead of index-by's last-wins collation?
(reduce #(if (get %1 (first %2)) %1 (assoc %1 (first %2) %2)) {} data)  ;trickier because you have to deal with the initial nil value case
(reduce #(update %1 (first %2) (fn [a b] (if (some? a) a b)) %2) {} data)
(into {} (reverse (map (juxt [first identity]) data)))
(-> (group-by first data) (update-vals first))  ;more clear, but inefficient

(group-with first (fn [a _] a) data)  ;much better symmetry with the last-wins case
(group-with first (partial unapply first) data)


;; What if you want to pick the winner based on some other criteria? E.g. max-key
(reduce #(assoc %1 (first %2) (max-key count %2 (get %1 (first %2)))) {} data)
(reduce #(update %1 (first %2) (partial max-key count) %2) {} data)
(-> (group-by first data) (update-vals (partial apply max-key count)))  ;more clear, but inefficient

(group-with first (partial max-key count) data)

;; Similar to with first-wins collation, min-key ends up being tricky because (= (count nil) 0), whereas group-with retains a nice symmetry with the max-key version

Add flip function

Some function I've used for a while, and maybe it could be useful to have available in the library for everybody is flip: some function that takes extra arguments as partial but moves the argument to the first position. Inspired by the name in other languages. I've mainly used it to mix well some functions that lend themselves to ->> or partial with the ones that work with ->.

(= (map #(assoc % :x 3) xs)
   (map (flip assoc :x 3) xs))
#_=> true
(map #(dissoc % :id :secret) xs)
(map (flip dissoc :id :secret) xs)
(map #(str/split % #"," -1) xs)
(map (flip str/split #"," -1) xs)

If we generalize it we can accept multiple arguments also in the generated function instead of just one. Inspired by the source code of clojure.core/partial: the function flip can take many arguments and only rearrange the first one in front of f, while leaving the rest behaving as in partial. Suggested definition based on partial:

(defn flip
  "Takes a function f and fewer than the normal arguments to f, and
  returns a fn that takes an additional arg. When called, the returned
  function calls f with the additional arg as first argument."
  [f & args]
  (fn [x] (apply f x args)))

;; examples with mathematical function
(mapv (flip / 3) (range 0 10 3)) #_=> [0 1 2 3]
(mapv (flip - 3) (range 0 10 3)) #_=> [-3 0 3 6]
;; but works with things that have a significant first argument like
update assoc dissoc str/split re-find ; etc.

Leaving it here for discussion (maybe this amount of flexibility is not needed, or the returned function should not accept 0-arity like partial, etc.). I can make a pull request if preferred.

Function request: join

I recently ran into a performance problem due to (apply concat ...) not being sufficiently lazy. Turns out, this has been a known issue for 4+ years. https://dev.clojure.org/jira/browse/CLJ-1218 and https://dev.clojure.org/jira/browse/CLJ-1583.

In the comments, it was pointed out that these problems could be avoided by just using a function called join that operates directly on a sequence of sequences.

(defn join
  "Lazily concatenates a sequence-of-sequences into a flat sequence."
  [s]
  (lazy-seq
   (when-let [s (seq s)] 
     (concat (first s) (join (rest s))))))

Given that this has been an issue for several years, I was wondering if you might consider inclusion of this join function into medley. Frankly, even if concat's behavior were eventually fixed in a future version of Clojure, I use (apply concat ...) so frequently that I'd like to have join as a convenient replacement for that pattern anyway.

filter-remove

I sometimes find myself wanting to split a collection into two groups: one group for which a predicate holds and one group for which the predicate doesn't hold. You can use group-by for this which would return a map with a true and false key, but after some benchmarking, this seems to be significantly faster:

(defn filter-remove [p xs]
  (loop [xs xs
         filtered (transient [])
         removed (transient [])]
    (if xs
      (let [x (first xs)] (if (p x)
                            (recur (next xs)
                                   (conj! filtered x) removed)
                            (recur (next xs) filtered (conj! removed x))))
      [(persistent! filtered) (persistent! removed)])))

(let [[odds evens] (filter-remove odd? (range 10))] [odds evens])
;;=> [[1 3 5 7 9] [0 2 4 6 8]]

If there's enough interest for this function, I can make a PR for it.

Suggested addition: ClojureCLR support

I think adding ClojureCLR support would be beneficial, especially in the greater effort to port Clojure(Script) libraries to ClojureCLR which doesn't seem to have nearly as fully developed support in terms of community libraries. I understand that adding support for ClojureCLR would be an ongoing commitment rather than a quick fix, but I would be willing to contribute time and effort where I can to maintaining these additions.

dissoc-in variable args

dissoc removes one or more keys from a map:

(dissoc {:foo 1 :bar 2 :baz 3} :foo :bar)

medley.core/dissoc-in takes only and exactly one key vector set:

(medley.core/dissoc-in {:a {:b 3 :c 4 :d 5}} [:a :b] [:a :c])
ArityException Wrong number of args (3) passed to: core/dissoc-in  clojure.lang.AFn.throwArity (AFn.java:429)

Does find-first belong?

I'm wondering if find-first belongs in this library.

I would argue against its inclusion because it is simple enough for anyone to write and is not any more clear than explicitly typing (first (filter pred coll)). Moreover, the simpler, composable method allows for find-last or remove-first and the like.

Contrast this with the difficulty of writing a performant version of map-keys.

Proposal: re-find-groups-seq

For Advent of Code I found I needed a function I'm calling re-find-groups-seq:

(re-find-groups-seq #"(\d+) (red|green|blue)"
                    "5 red, 2 green, 1 blue")
=>
([{:match "5", :within "5 red", :start 0, :end 1} {:match "red", :within "5 red", :start 2, :end 5}]
 [{:match "2", :within "2 green", :start 7, :end 8} {:match "green", :within "2 green", :start 9, :end 14}]
 [{:match "1", :within "1 blue", :start 16, :end 17} {:match "blue", :within "1 blue", :start 18, :end 22}])

Essentially, it's re-seq, but on each match, you get a vector of maps, not strings; the maps identify where in the input string the pattern group matched.

So if there's interest, I'm quite happy to add docs and tests and submit as a PR.

Function request(s): Add/Remove element at index in vector

When working with UIs that need specific order, a vector makes sense.

But also the ability to remove or insert entries anywhere in the vector, which is also important for UI work. Arguably, an RRB vector might be more efficient, but for few entries (no more than 10) a vector should be just as fine, if not faster.

Something like (taken literally from the top stack overflow answers):


(defn vec-insert
  [v n e] 
  (vec (concat (subvec v 0 n) [e] (subvec v n))))

(defn vec-remove
  [v n]
  (vec (concat (subvec v 0 n) (subvec v (inc n)))))

Add conj-some fn

Good afternoon. Thanks for your great set of tools. I wanted to know what you think about adding a conj-some feature similar to a conj-when in plumbing, but only if it's not nil, not for all falsey values . It seems enough general-purpose for me.
With this can do thigs like this and this looks to me to continue the logic of your library

(reduce conj-some [] [:a (when (true? false-x) :b)]
=> [:a] ;;; not [:a nil] with regular conj

select-some

Would you be interested in a PR for this?

(defn select-some
  "Like select-keys, but only selects when value is not nil."
  ([m ks]
   (persistent!
    (reduce (fn [acc k]
              (if-some [v (get m k)]
                (assoc! acc k v)
                acc))
            (transient {})
            ks))))

;; example:
(select-some {:a 1 :b nil :c 2 :d false} [:a :b :d]) ;; => {:a 1, :d false}

map-vals, map-keys & map-kv raise an exception when called on a record

The functions map-vals, map-keys and map-kv all raise an error when called on a record e.g.

(defrecord Foo [bar])

(medley/map-vals str (->Foo 1))

Raises the exception below because reduce-map calls empty on the record.

1. Unhandled java.lang.UnsupportedOperationException
   Can't create empty: user.Foo

                      REPL:  214  userl.Foo/empty
                  core.clj: 5043  clojure.core/empty
                  core.clj: 5037  clojure.core/empty
                 core.cljc:   50  medley.core$reduce_map/invokeStatic
                 core.cljc:   47  medley.core$reduce_map/invoke
                 core.cljc:   73  medley.core$map_vals/invokeStatic
                 core.cljc:   70  medley.core$map_vals/invoke
                      REPL:  218  user/eval36135
                      REPL:  218  user/eval36135
             Compiler.java: 6927  clojure.lang.Compiler/eval
             Compiler.java: 6890  clojure.lang.Compiler/eval
                  core.clj: 3105  clojure.core/eval
                  core.clj: 3101  clojure.core/eval
                  main.clj:  240  clojure.main/repl/read-eval-print/fn
                  main.clj:  240  clojure.main/repl/read-eval-print
                  main.clj:  258  clojure.main/repl/fn
                  main.clj:  258  clojure.main/repl
                  main.clj:  174  clojure.main/repl
               RestFn.java:  137  clojure.lang.RestFn/applyTo
                  core.clj:  646  clojure.core/apply
                  core.clj:  641  clojure.core/apply
                regrow.clj:   18  refactor-nrepl.ns.slam.hound.regrow/wrap-clojure-repl/fn
               RestFn.java: 1523  clojure.lang.RestFn/invoke
    interruptible_eval.clj:   87  clojure.tools.nrepl.middleware.interruptible-eval/evaluate/fn
                  AFn.java:  152  clojure.lang.AFn/applyToHelper
                  AFn.java:  144  clojure.lang.AFn/applyTo
                  core.clj:  646  clojure.core/apply
                  core.clj: 1881  clojure.core/with-bindings*
                  core.clj: 1881  clojure.core/with-bindings*
               RestFn.java:  425  clojure.lang.RestFn/invoke
    interruptible_eval.clj:   85  clojure.tools.nrepl.middleware.interruptible-eval/evaluate
    interruptible_eval.clj:   55  clojure.tools.nrepl.middleware.interruptible-eval/evaluate
    interruptible_eval.clj:  222  clojure.tools.nrepl.middleware.interruptible-eval/interruptible-eval/fn/fn
    interruptible_eval.clj:  190  clojure.tools.nrepl.middleware.interruptible-eval/run-next/fn
                  AFn.java:   22  clojure.lang.AFn/run
   ThreadPoolExecutor.java: 1142  java.util.concurrent.ThreadPoolExecutor/runWorker
   ThreadPoolExecutor.java:  617  java.util.concurrent.ThreadPoolExecutor$Worker/run
               Thread.java:  745  java.lang.Thread/run

insert-nth: ability to use negative numbers

Hi. First of all thx for great tooling.

(require '[medley.core :as medley])
;; Proposal
(let [coll [1 2 3 4 5]]
         (medley/insert-nth -1 :a coll))
;; Suggests the same result as
(let [coll [1 2 3 4 5]
             coll-len (count coll)]
         (medley/insert-nth (dec coll-len) :a coll))
;; => (1 2 3 4 :a 5)

Suggested addition: index-and-map-by

Wondering if you'd be open to a function index-and-map-by generalizing over index-by like the following:

(defn index-and-map-by
  [kf vf coll]
  (into {} 
    (map 
      (fn [x]
        [(kf x) (vf x)]))
    coll))

(Of course, you might want to improve the peformance of this implementation, e.g with reduce and transients).

(index-and-map-by kf vf coll) would be equivalent to (->> coll (index-by kf) (map-vals vf))

I'm asking because I keep defining this index-and-map-by function in my projects.

Renaming keys in an associative collection by applying a fn

Would that be something suitable for this library? Lately I've been needing a function like this:

(defn rename-keys [f coll]
  (zipmap (map f (keys coll))
          (vals coll)))

I'm not sure if that is a good name as it might be confused with clojure.set/rename-keys. What do you think?

Additional map-transformation functions

Would you consider adding the following:

  • map-vals-with-keys :: (K -> V -> V') -> Map[K, V] -> Map[K, V'] (or map-kv-vals)
  • map-keys-with-vals :: (K -> V -> K') -> Map[K, V] -> Map[K', V] (or map-kv-keys)

?

I seem to run into the former all the time and doing map-kv always seems unnecessary.

Suggested addition: update-items

First off, this might be out of scope for the project, but I do think it is a powerful addition and still fits under pure, and general purpose. Second, I'm not sure if my implementation is the most performant, nor if the name is the best.

Rationale

It is very common to find highly nested data-structures.
This is why get-in, assoc-in, and update-in exist.

Unfortunately, these fall apart if you need to process items of a collection within the structure. Even worse is if you have a multiple collections to in the tree. I believe this difficulty was a major motivator for large DSLs like meander or spectre.

I've been using this function for a number of years and find it invaluable when I know the shape of a data-structure but need to traverse collections and update-in is insufficient.

Comparison

Here's an example, if I have a map with users, that have orders, that have items, that each have a price

{:users [{:id 1 :orders #{{:items [{:price 1} {:price 4} {:price 2}]}}}
         {:id 2 :orders #{}}]}

Suppose you want to change all the item prices to strings with a dollar sign pre-pended. You'd need to do something like:

(update
  {:users [{:id 1 :orders #{{:items [{:price 1} {:price 4} {:price 2}]}}}
           {:id 2 :orders #{}}]}
  :users
  (fn [users]
    (mapv (fn [user]
            (update user :orders (fn [orders]
                                   (set (map (fn [order]
                                               (update order :items (fn [items]
                                                                      (mapv (fn [item]
                                                                              (update item :price #(str "$" %)))
                                                                            items))))
                                             orders)))))
          users)))
;; =>
{:users [{:id 1, :orders #{{:items [{:price "$1"} {:price "$4"} {:price "$2"}]}}} 
         {:id 2, :orders #{}}]}          

Writing this example out, I made a number of mistakes: I tried to nest function literals, I forgot to pass the coll to many of the map calls, I forgot that :orders is supposed to be a set.

Here's the signature for update-items, similar to update but coll-k points at a collection and item-update-fn is applied to each item in the collection.

(defn update-items [m coll-k item-update-fn & item-update-args])

Using this, our highly nested, tedious, and error-prone processing can flatten out completely.

(update-items
  {:users [{:id 1 :orders #{{:items [{:price 1} {:price 4} {:price 2}]}}}
           {:id 2 :orders #{}}]}
  :users
  update-items
  :orders
  update-items
  :items
  update
  :price
  #(str "$" %))
;; =>
{:users [{:id 1, :orders #{{:items [{:price "$1"} {:price "$4"} {:price "$2"}]}}} 
         {:id 2, :orders #{}}]}          

POC Implementation

(defn update-items*
  [m k mapping-fn item-update-fn & item-update-args]
  (update m k
          (fn [coll]
            (mapping-fn (fn [item]
                          (apply item-update-fn item item-update-args))
                        coll))))

(defn update-items
  [m k item-update-fn & item-update-args]
  (apply update-items*
         m
         k
         (fn [mapper coll]
           (into (empty coll) (map mapper) coll))
         item-update-fn
         item-update-args))

This could be written without update-items* but being able to pass the mapping-fn can be useful:

(update-items*
  {:users [{:id 1 :orders #{{:items [{:price 1} {:price 4} {:price 2}]}}}
           {:id 2 :orders #{}}]}
  :users
  (comp #(filterv (comp seq :orders) %) map)
  update-items
  :orders
  update-items*
  :items
  (comp vec #(sort-by :price %) filterv)
  (comp even? :price))
;; =>
{:users [{:id 1, :orders #{{:items [{:price 2} {:price 4}]}}}]}

NPE from assoc-some if map is nil and there is more than one key supplied

It used to be the case that the map passed to assoc-some could be nil, but the recent changes made to improve performance mean this now doesn't work if more than one key is supplied.

e.g.:

(medley/assoc-some nil :k "v")
;; => {:k "v"}

but

(medley/assoc-some nil :k1 "v1" :k2 "v2")
;; => java.lang.NullPointerException

I don't know if we're supposed to rely on the behaviour of assoc-some (or even Clojure core's assoc) when the supplied map is nil as it's not specifically documented from what I can see, but looking at the Java implementation of assoc it does specifically check for null and return a new map in that case. Obviously feel free to close this if you don't feel it's documented behaviour.

Thanks!

Suggested addition: mapmap

(your issue template might be broken btw)

like map, but one level deeper.
Given a sequence (lvl1) of sequences (lvl2), map function to those sequences (lvl2) of the sequence.
Especially useful because you can't nest short form lambdas #(fn %)

Suggested addition: replace-subvec

When you need to put a vector into another vector, from start until the end of the vector to insert.

(defn replace-subvec [v v2 index]
  {:pre [(vector? v)
         (vector? v2)
         (integer? index)]}
  (let [v-count (count v)
        index (if (<= index v-count)
                index v-count)]
    (persistent!
      (reduce-kv
        (fn [acc i el]
          (assoc! acc (+ i index) el))
        (transient v) v2))))

Incompatibility between medley/medley and dev.weavejester/medley

I recently started getting an error after deploying that m/partition-between could not be found.

That was strange, because I only had dev.weavejester/medley {:mvn/version "1.7.0"} in my deps.edn.

This took quite a bit of digging, but what I finally discovered is that several of my other dependencies still had dependencies on various old versions of medley/medley

Because Clojure/Java doesn't know that they are the same package, both were included in the classpath, which caused the old medley.core to take precedence in some cases, which meant that the m/partition-between function was not available.

The fix for me was to run clj -Stree to get a tree of all my dependencies, and then add :exclusions [medley/medley] to all the other dependencies that use the old medley versions. This a bit error-prone, as all new dependencies have to be checked, as well as any dependencies of those dependencies.

I'd be interested in any better suggestions for dealing with this issue.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.