Comments (12)
(defmacro mfn [ctx & body]
`(with-meta (fn ~@body) {:cats.core/context ~ctx}))
(let [m* (mfn maybe/maybe-monad
[x y]
(if (odd? y)
(maybe/nothing)
(maybe/just (* x y))))]
(m* 6 7)
;; => #<Just 42>
(= (::context (meta m*)) maybe/maybe-monad)
;; => true
:ok)
;; Example precondition
{:pre [(->> (get (meta f) ::context) (satisfies? p/Monad))]}
from cats.
i was just bitten badly by context management (made worse by the renaming of cats -> funcool/cats, and transitive deps causing 2 conflicting versions of cats being loaded unbeknownst to me)
putting the context into metadata was my first thought for a solution... figuring out where a missing context is when it's a simple metadata value will probably be easier than wondering why a dynamic var isn't being set or where it should be set
from cats.
In my opinion, having the ability to extract context from the metadata seems a nice idea. Just +1
from cats.
I agree with using metadata for extracting the context of a value. One thing that is clumsy to use in cats are monad transformers and I think metadata could improve their usability.
from cats.
Pushed some experimental code here: https://github.com/yurrriq/cats/tree/context-meta
I plan to refine and add test sometime soon.
from cats.
I've added a first pass at defmfn
. It would enable:
(require '[cats.context :as ctx]
'[cats.monad.maybe :as maybe])
(m/defmfn maybe/context m-div
([x y]
(if (zero? y)
(maybe/nothing)
(maybe/just (/ x y))))
([x y z]
(m/bind (m-div x y)
#(m-div % z))))
(m-div 1 2)
;; => #<Just 1/2>
(m-div 1 2 3)
;; => #<Just 1/6>
(meta #'m-div)
;; => {:arglists ([x y] [x y z]), :name m-div}
... and, assuming a redefined foldm
:
(defn foldm
([f z xs]
(if (empty? xs)
(if (satisfies? p/Contextual f) ; added
(return (p/-get-context f) z) ; added
(return z))
(let [[h & t] xs]
(mlet [z' (f z h)]
(if (empty? t)
(return z')
(foldm f z' t))))))
([ctx f z xs]
(if (empty? xs)
(return ctx z)
(foldm f z xs))))
(m/foldm m-div 1 [])
;; => #<Just 1>
Potentially contentious:
(p/-get-context m-div)
;; => #<Maybe>
vs
user> (p/-get-context (fn [] ))
;; => #<Function>
/end thought dump
After all this, I'm starting to like the meta approach better, I think... What are your thoughts?
from cats.
Also, it's probably not worth all the trouble to mimic defn
metadata/docstring handling so closely... I have mixed feelings about the hacky clojure.lang.IFn
implementation too.
Seriously, maybe the metadata approach is best.
from cats.
I mean, the context issues are largely solved by Context
and Contextual
anyway. The only tricky part is declaring/inferring that a certain function returns a certain monad.
from cats.
One final thought is that I'd love to do away with *context*
if possible.
from cats.
I think that using metadata would be a proper approach, this will simplify the defmfn
macro I think. In any case nice results!
Later, I think removing context would be not possible, because that in some way may force user define functions with a defmfn
or similar macros and is to much opinionated and for simple use case such as error control with maybe and either is to much overkill to the user experience.
Using dynamic scope is not to much evil if it is used in a controlled way and I think that it (in cats) plays very well.
from cats.
Thanks for the feedback. I agree with all your points. I'll be fleshing out the meta approach instead.
from cats.
I'm reading this over again. Hopefully, I can work on it soon.
from cats.
Related Issues (20)
- Why is the implementation of rights not extracting the values from right? HOT 4
- No such namespace: promesa.impl.proto (required from cats.labs.promise) HOT 1
- haskell's sequence HOT 2
- foldl Documentation Example fail HOT 1
- lift-a produces an exception when n is (inc 1) but not when n is 2 HOT 1
- maybe/nothing doesn't have to be a function
- Please release fmap fix HOT 10
- doc for fapply - wrap in the same context as af?
- Documentation is broken HOT 3
- Reflections in the state monad HOT 3
- 2.3.0 not available on clojars HOT 6
- Missing tag 2.3.1 HOT 1
- Can't build the 2.3.1: failed compiling file:src/cats/monad/state.cljc HOT 1
- Naming conventions
- Add a jupyter notebook with the documentation. HOT 2
- cats.labs.promise support for promesa 2.x
- Error printing return value of try monad in REPL HOT 3
- Apparent inconsistent behaviour of alet compared to mlet HOT 2
- Code examples in the documentation don't return what's expected
- Cats does not work with new versions of Promesa
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
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.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from cats.