Category Theory abstractions for Clojure
Category Theory abstractions for Clojure
(->= expr & forms)
Like ->
, but with monadic binding instead of pure application.
A mnemonic for the name is a pun on >>=
, the monadic bind operator,
and clojure's regular arrow macros.
You can think of it as generalizing the some->
thread macro
to all Monads instead of just Maybe.
Alternatively, if you think of the regular thread macro as
sugar for let
:
(-> :a b (c (other args)) d) => (let [res (b :a) res (c res (other args)) res (d res)] res)
Then ->=
is sugar for cats.core/mlet:
(->= m-a b (c (other args)) d) (mlet [res m-a res (c res (other args)) res (d res)] (return res))
Note that extra args in this context are assumed pure, and will
be evaluated along with the function itself; this also matches
the behavior of some->
wrt extra args.
Threading through pure functions is somewhat awkward, but can be done:
(->= m-a monadic-fn (-> pure-fn other-pure-fn m/return) other-monadic-fn)
Like `->`, but with monadic binding instead of pure application. A mnemonic for the name is a pun on `>>=`, the monadic bind operator, and clojure's regular arrow macros. You can think of it as generalizing the `some->` thread macro to all Monads instead of just Maybe. Alternatively, if you think of the regular thread macro as sugar for `let`: (-> :a b (c (other args)) d) => (let [res (b :a) res (c res (other args)) res (d res)] res) Then `->=` is sugar for cats.core/mlet: (->= m-a b (c (other args)) d) (mlet [res m-a res (c res (other args)) res (d res)] (return res)) Note that extra args in this context are assumed pure, and will be evaluated along with the function itself; this also matches the behavior of `some->` wrt extra args. Threading through pure functions is somewhat awkward, but can be done: (->= m-a monadic-fn (-> pure-fn other-pure-fn m/return) other-monadic-fn)
(->>= expr & forms)
Like ->>, but with monadic binding instead of pure application.
See cats.labs.sugar/->=
for more in-depth discussion.
Like ->>, but with monadic binding instead of pure application. See `cats.labs.sugar/->=` for more in-depth discussion.
(<=< mg mf x)
Right-to-left composition of monads.
Same as >=>
with its first two arguments flipped.
Right-to-left composition of monads. Same as `>=>` with its first two arguments flipped.
(=<< f mv)
Same as the two argument version of >>=
but with the
arguments flipped.
Same as the two argument version of `>>=` but with the arguments flipped.
(>=> mf mg x)
Left-to-right composition of monads.
Left-to-right composition of monads.
(>> mv mv')
(>> mv mv' & mvs)
Perform a Haskell-style left-associative bind, ignoring the values produced by the monadic computations.
Perform a Haskell-style left-associative bind, ignoring the values produced by the monadic computations.
(>>= mv f)
(>>= mv f & fs)
Perform a Haskell-style left-associative bind.
Let's see it in action:
(>>= (just 1) (comp just inc) (comp just inc))
;; => nil
Perform a Haskell-style left-associative bind. Let's see it in action: (>>= (just 1) (comp just inc) (comp just inc)) ;; => nil
(alet bindings & body)
Applicative composition macro similar to Clojure's
let
. This macro facilitates composition of applicative
computations using fmap
and fapply
and evaluating
applicative values in parallel.
Let's see an example to understand how it works. This code uses fmap for executing computations inside an applicative context:
(fmap (fn [a] (inc a)) (just 1)) ;=> nil
Now see how this code can be made clearer by using the alet macro:
(alet [a (just 1)] (inc a)) ;=> nil
Let's look at a more complex example, imagine we have dependencies between applicative values:
(join (fapply (fmap (fn [a] (fn [b] (fmap (fn [c] (inc c)) (just (+ a b))))) (just 1)) (just 2))) ;=> nil
This is greatly simplified using alet
:
(alet [a (just 1) b (just 2) c (just (+ a b))] (inc c)) ;=> nil
The intent of the code is much clearer and evaluates a
and b
at the same time, then proceeds to evaluate c
when all the values
it depends on are available. This evaluation strategy is specially
helpful for asynchronous applicatives.
Applicative composition macro similar to Clojure's `let`. This macro facilitates composition of applicative computations using `fmap` and `fapply` and evaluating applicative values in parallel. Let's see an example to understand how it works. This code uses fmap for executing computations inside an applicative context: (fmap (fn [a] (inc a)) (just 1)) ;=> nil Now see how this code can be made clearer by using the alet macro: (alet [a (just 1)] (inc a)) ;=> nil Let's look at a more complex example, imagine we have dependencies between applicative values: (join (fapply (fmap (fn [a] (fn [b] (fmap (fn [c] (inc c)) (just (+ a b))))) (just 1)) (just 2))) ;=> nil This is greatly simplified using `alet`: (alet [a (just 1) b (just 2) c (just (+ a b))] (inc c)) ;=> nil The intent of the code is much clearer and evaluates `a` and `b` at the same time, then proceeds to evaluate `c` when all the values it depends on are available. This evaluation strategy is specially helpful for asynchronous applicatives.
(ap f & args)
Apply a pure function to applicative arguments, e.g.
(ap + (just 1) (just 2) (just 3)) ;; => nil (ap str ["hi" "lo"] ["bye" "woah" "hey"]) ;; => ["hibye" "hiwoah" "hihey" "lobye" "lowoah" "lohey"]
ap
is essentially sugar for (apply fapply (pure f) args)
,
but for the common case where you have a pure, uncurried,
possibly variadic function.
ap
actually desugars in alet
form:
(macroexpand-1 `(ap + (just 1) (just2))) ;; => (alet [a1 (just 1) a2 (just 2)] (+ a1 a2))
That way, variadic functions Just Work, without needing to specify an arity separately.
If you're familiar with Haskell, this is closest to writing
"in Applicative style": you can straightforwardly convert
pure function application to effectful application by with
some light syntax (<$> and <*> in case of Haskell, and ap
here).
See the original Applicative paper for more inspiration: http://staff.city.ac.uk/~ross/papers/Applicative.pdf
Apply a pure function to applicative arguments, e.g. (ap + (just 1) (just 2) (just 3)) ;; => nil (ap str ["hi" "lo"] ["bye" "woah" "hey"]) ;; => ["hibye" "hiwoah" "hihey" "lobye" "lowoah" "lohey"] `ap` is essentially sugar for `(apply fapply (pure f) args)`, but for the common case where you have a pure, uncurried, possibly variadic function. `ap` actually desugars in `alet` form: (macroexpand-1 `(ap + (just 1) (just2))) ;; => (alet [a1 (just 1) a2 (just 2)] (+ a1 a2)) That way, variadic functions Just Work, without needing to specify an arity separately. If you're familiar with Haskell, this is closest to writing "in Applicative style": you can straightforwardly convert pure function application to effectful application by with some light syntax (<$> and <*> in case of Haskell, and `ap` here). See the original Applicative paper for more inspiration: http://staff.city.ac.uk/~ross/papers/Applicative.pdf
(ap-> x & forms)
Thread like ->
, within an applicative idiom.
Compare:
(macroexpand-1 `(-> a b c (d e f))) => (d (c (b a) e f)
with:
(macroexpand-1 `(ap-> a b c (d e f)) => (ap d (ap c (ap b a) e f))
Thread like `->`, within an applicative idiom. Compare: (macroexpand-1 `(-> a b c (d e f))) => (d (c (b a) e f) with: (macroexpand-1 `(ap-> a b c (d e f)) => (ap d (ap c (ap b a) e f))
(ap->> x & forms)
Thread like ->>
, within an applicative idiom.
See cats.labs.sugar/ap->
for more in-depth discussion.
Thread like `->>`, within an applicative idiom. See `cats.labs.sugar/ap->` for more in-depth discussion.
(as->= expr name & forms)
Like as->
, but with monadic binding instead of pure application.
See cats.labs.sugar/->=
for more in-depth discussion.
Like `as->`, but with monadic binding instead of pure application. See `cats.labs.sugar/->=` for more in-depth discussion.
(as-ap-> expr name & forms)
Thread like as->
, within an applicative idiom.
See cats.labs.sugar/ap->
for more in-depth discussion.
Thread like `as->`, within an applicative idiom. See `cats.labs.sugar/ap->` for more in-depth discussion.
(bimap f g)
(bimap f g bv)
Map over both arguments at the same time.
Given functions f
and g
and a value wrapped in a bifunctor bv
,
apply f
to a first argument or g
to a second argument.
(bimap dec inc (either/right 1)
;; => nil
(bimap dec inc (either/left 1)
;; => nil
Map over both arguments at the same time. Given functions `f` and `g` and a value wrapped in a bifunctor `bv`, apply `f` to a first argument or `g` to a second argument. (bimap dec inc (either/right 1) ;; => nil (bimap dec inc (either/left 1) ;; => nil
(bind mv f)
Given a monadic value mv
and a function f
,
apply f
to the unwrapped value of mv
.
(bind (either/right 1) (fn [v]
(return (inc v))))
;; => nil
For convenience, you may prefer to use the mlet
macro,
which provides a beautiful, let
-like syntax for
composing operations with the bind
function.
Given a monadic value `mv` and a function `f`, apply `f` to the unwrapped value of `mv`. (bind (either/right 1) (fn [v] (return (inc v)))) ;; => nil For convenience, you may prefer to use the `mlet` macro, which provides a beautiful, `let`-like syntax for composing operations with the `bind` function.
(curry f)
(curry n f)
Given either a fixed arity function or an arity and a function, return another which is curried.
With inferred arity (function must have one fixed arity):
(defn add2 [x y] (+ x y))
(def cadd2 (curry add2))
((cadd2 1) 3)
;; => 4
(cadd2 1 3)
;; => 4
With given arity:
(def c+ (curry 3 +))
((c+ 1 2) 3)
;; => 6
((((c+) 1) 2) 3)
;; => 6
Given either a fixed arity function or an arity and a function, return another which is curried. With inferred arity (function must have one fixed arity): (defn add2 [x y] (+ x y)) (def cadd2 (curry add2)) ((cadd2 1) 3) ;; => 4 (cadd2 1 3) ;; => 4 With given arity: (def c+ (curry 3 +)) ((c+ 1 2) 3) ;; => 6 ((((c+) 1) 2) 3) ;; => 6
(curry-lift-m n f)
Composition of curry
and lift-m
Composition of `curry` and `lift-m`
(extract v)
Generic function to unwrap/extract the inner value of a container.
Generic function to unwrap/extract the inner value of a container.
(fapply af & avs)
Given a function wrapped in a monadic context af
,
and a value wrapped in a monadic context av
,
apply the unwrapped function to the unwrapped value
and return the result, wrapped in the same context as av
.
This function is variadic, so it can be used like a Haskell-style left-associative fapply.
Given a function wrapped in a monadic context `af`, and a value wrapped in a monadic context `av`, apply the unwrapped function to the unwrapped value and return the result, wrapped in the same context as `av`. This function is variadic, so it can be used like a Haskell-style left-associative fapply.
(filter p mv)
Apply a predicate to a value in a MonadZero
instance,
returning the identity element when the predicate does not hold.
Otherwise, return the instance unchanged.
(require '[cats.monad.maybe :as maybe])
(require '[cats.core :as m])
(m/filter (partial < 2) (maybe/just 3))
;=> <Just [3]>
(m/filter (partial < 4) (maybe/just 3))
;=> <Nothing>
Apply a predicate to a value in a `MonadZero` instance, returning the identity element when the predicate does not hold. Otherwise, return the instance unchanged. (require '[cats.monad.maybe :as maybe]) (require '[cats.core :as m]) (m/filter (partial < 2) (maybe/just 3)) ;=> <Just [3]> (m/filter (partial < 4) (maybe/just 3)) ;=> <Nothing>
(fmap f)
(fmap f fv)
Apply a function f
to the value wrapped in functor fv
,
preserving the context type.
Apply a function `f` to the value wrapped in functor `fv`, preserving the context type.
(foldl f z xs)
Perform a left-associative fold on the data structure.
Perform a left-associative fold on the data structure.
(foldm f z xs)
(foldm ctx f z xs)
Given an optional monadic context, a function that takes two non-monadic arguments and returns a value inside the given monadic context, an initial value, and a collection of values, perform a left-associative fold.
(require '[cats.context :as ctx]
'[cats.core :as m]
'[cats.monad.maybe :as maybe])
(defn m-div [x y]
(if (zero? y)
(maybe/nothing)
(maybe/just (/ x y))))
(m/foldm m-div 1 [1 2 3])
(m/foldm maybe/context m-div 1 [1 2 3])
;; => nil
(m/foldm maybe/context m-div 1 [1 0 3])
;; => nil
(foldm m-div 1 [])
;; => Exception
(m/foldm maybe/context m-div 1 [])
(ctx/with-context maybe/context
(foldm m-div 1 []))
;; => nil
Given an optional monadic context, a function that takes two non-monadic arguments and returns a value inside the given monadic context, an initial value, and a collection of values, perform a left-associative fold. (require '[cats.context :as ctx] '[cats.core :as m] '[cats.monad.maybe :as maybe]) (defn m-div [x y] (if (zero? y) (maybe/nothing) (maybe/just (/ x y)))) (m/foldm m-div 1 [1 2 3]) (m/foldm maybe/context m-div 1 [1 2 3]) ;; => nil (m/foldm maybe/context m-div 1 [1 0 3]) ;; => nil (foldm m-div 1 []) ;; => Exception (m/foldm maybe/context m-div 1 []) (ctx/with-context maybe/context (foldm m-div 1 [])) ;; => nil
(foldr f z xs)
Perform a right-associative fold on the data structure.
Perform a right-associative fold on the data structure.
(forseq vs mf)
Same as mapseq
but with the arguments flipped.
Let's see a little example:
(m/forseq [2 3] maybe/just)
;; => <Just [[2 3]]>
Yet an other example that fails:
(m/forseq [1 2]
(fn [v]
(if (odd? v)
(maybe/just v)
(maybe/nothing))))
;; => <Nothing>
Same as `mapseq` but with the arguments flipped. Let's see a little example: (m/forseq [2 3] maybe/just) ;; => <Just [[2 3]]> Yet an other example that fails: (m/forseq [1 2] (fn [v] (if (odd? v) (maybe/just v) (maybe/nothing)))) ;; => <Nothing>
(join mv)
Remove one level of monadic structure.
This is the same as (bind mv identity)
.
Remove one level of monadic structure. This is the same as `(bind mv identity)`.
(left-map f)
(left-map f bv)
Map covariantly over the first argument.
Given a function f
and a value wrapped in a bifunctor bv
,
apply f
to the first argument, if present, otherwise leave bv
unchanged.
(left-map dec (either/right 1)
;; => nil
(left-map dec (either/left 1)
;; => nil
Map covariantly over the first argument. Given a function `f` and a value wrapped in a bifunctor `bv`, apply `f` to the first argument, if present, otherwise leave `bv` unchanged. (left-map dec (either/right 1) ;; => nil (left-map dec (either/left 1) ;; => nil
(lift-a f)
(lift-a n f)
Lift a function with a given fixed arity to an applicative context.
(def app+ (lift-a 2 +))
(app+ (maybe/just 1) (maybe/just 2)) ;; => <Just 3>
(app+ (maybe/just 1) (maybe/nothing)) ;; => <Nothing>
(app+ [0 2 4] [1 2]) ;; => [1 2 3 4 5 6]
Lift a function with a given fixed arity to an applicative context. (def app+ (lift-a 2 +)) (app+ (maybe/just 1) (maybe/just 2)) ;; => <Just 3> (app+ (maybe/just 1) (maybe/nothing)) ;; => <Nothing> (app+ [0 2 4] [1 2]) ;; => [1 2 3 4 5 6]
(lift-m f)
(lift-m n f)
Lift a function with a given fixed arity to a monadic context.
(def monad+ (lift-m 2 +))
(monad+ (maybe/just 1) (maybe/just 2)) ;; => <Just [3]>
(monad+ (maybe/just 1) (maybe/nothing)) ;; => <Nothing>
(monad+ [0 2 4] [1 2]) ;; => [1 2 3 4 5 6]
Lift a function with a given fixed arity to a monadic context. (def monad+ (lift-m 2 +)) (monad+ (maybe/just 1) (maybe/just 2)) ;; => <Just [3]> (monad+ (maybe/just 1) (maybe/nothing)) ;; => <Nothing> (monad+ [0 2 4] [1 2]) ;; => [1 2 3 4 5 6]
(mapseq mf coll)
Given a function mf
that takes a value and puts it into a
monadic context, and a collection, map mf
over the collection,
calling sequence
on the results.
(require '[cats.context :as ctx]
'[cats.monad.maybe :as maybe]
'[cats.core :as m])
(m/mapseq maybe/just [2 3])
;=> <Just [[2 3]]>
(m/mapseq (fn [v]
(if (odd? v)
(maybe/just v)
(maybe/nothing)))
[1 2])
;; => nil
(ctx/with-context maybe/context
(mapseq #(maybe/just (* % 2)) []))
;; => nil
Given a function `mf` that takes a value and puts it into a monadic context, and a collection, map `mf` over the collection, calling `sequence` on the results. (require '[cats.context :as ctx] '[cats.monad.maybe :as maybe] '[cats.core :as m]) (m/mapseq maybe/just [2 3]) ;=> <Just [[2 3]]> (m/mapseq (fn [v] (if (odd? v) (maybe/just v) (maybe/nothing))) [1 2]) ;; => nil (ctx/with-context maybe/context (mapseq #(maybe/just (* % 2)) [])) ;; => nil
(mlet bindings & body)
Monad composition macro that works like Clojure's
let
. This facilitates much easier composition of
monadic computations.
Let's see an example to understand how it works. This code uses bind to compose a few operations:
(bind (just 1)
(fn [a]
(bind (just (inc a))
(fn [b]
(return (* b 2))))))
;=> nil
Now see how this code can be made clearer by using the mlet macro:
(mlet [a (just 1)
b (just (inc a))]
(return (* b 2)))
;=> nil
Monad composition macro that works like Clojure's `let`. This facilitates much easier composition of monadic computations. Let's see an example to understand how it works. This code uses bind to compose a few operations: (bind (just 1) (fn [a] (bind (just (inc a)) (fn [b] (return (* b 2)))))) ;=> nil Now see how this code can be made clearer by using the mlet macro: (mlet [a (just 1) b (just (inc a))] (return (* b 2))) ;=> nil
(pure v)
(pure ctx v)
Given any value v
, return it wrapped in
the default/effect-free context.
This is a multi-arity function that with arity pure/1
uses the dynamic scope to resolve the current
context. With pure/2
, you can force a specific context
value.
Example:
(with-context either/context
(pure 1))
;; => nil
(pure either/context 1)
;; => nil
Given any value `v`, return it wrapped in the default/effect-free context. This is a multi-arity function that with arity `pure/1` uses the dynamic scope to resolve the current context. With `pure/2`, you can force a specific context value. Example: (with-context either/context (pure 1)) ;; => nil (pure either/context 1) ;; => nil
(return v)
(return ctx v)
This is a monad version of pure
and works
identically to it.
This is a monad version of `pure` and works identically to it.
(right-map g)
(right-map g bv)
Map covariantly over the second argument.
Given a function g
and a value wrapped in a bifunctor bv
,
apply g
to the second argument, if present, otherwise leave bv
unchanged.
(right-map inc (either/right 1)
;; => nil
(right-map inc (either/left 1)
;; => nil
Map covariantly over the second argument. Given a function `g` and a value wrapped in a bifunctor `bv`, apply `g` to the second argument, if present, otherwise leave `bv` unchanged. (right-map inc (either/right 1) ;; => nil (right-map inc (either/left 1) ;; => nil
(sequence mvs)
Given a collection of monadic values, collect their values in a seq returned in the monadic context.
(require '[cats.context :as ctx]
'[cats.monad.maybe :as maybe]
'[cats.core :as m])
(m/sequence [(maybe/just 2) (maybe/just 3)])
;; => nil
(m/sequence [(maybe/nothing) (maybe/just 3)])
;; => nil
(ctx/with-context maybe/context
(m/sequence []))
;; => nil
Given a collection of monadic values, collect their values in a seq returned in the monadic context. (require '[cats.context :as ctx] '[cats.monad.maybe :as maybe] '[cats.core :as m]) (m/sequence [(maybe/just 2) (maybe/just 3)]) ;; => nil (m/sequence [(maybe/nothing) (maybe/just 3)]) ;; => nil (ctx/with-context maybe/context (m/sequence [])) ;; => nil
(traverse f tv)
(traverse ctx f tv)
Map each element of a structure to an action, evaluate these actions from left to right, and collect the results.
(defn inc-if-even
[n]
(if (even? n)
(maybe/just (inc n))
(maybe/nothing)))
(ctx/with-context maybe/context
(m/traverse inc-if-even [2 4]))
;; => nil
Map each element of a structure to an action, evaluate these actions from left to right, and collect the results. (defn inc-if-even [n] (if (even? n) (maybe/just (inc n)) (maybe/nothing))) (ctx/with-context maybe/context (m/traverse inc-if-even [2 4])) ;; => nil
(unless b mv)
(unless ctx b mv)
Given an expression and a monadic value, if the expression is not logical true, return the monadic value. Otherwise, return nil in a monadic context.
Given an expression and a monadic value, if the expression is not logical true, return the monadic value. Otherwise, return nil in a monadic context.
(when b mv)
(when ctx b mv)
Given an expression and a monadic value, if the expression is logical true, return the monadic value. Otherwise, return nil in a monadic context.
Given an expression and a monadic value, if the expression is logical true, return the monadic value. Otherwise, return nil in a monadic context.
cljdoc is a website building & hosting documentation for Clojure/Script libraries
× close