uncomplicate / fluokitten Goto Github PK
View Code? Open in Web Editor NEWCategory theory concepts in Clojure - Functors, Applicatives, Monads, Monoids and more.
Home Page: http://fluokitten.uncomplicate.org
License: Eclipse Public License 1.0
Category theory concepts in Clojure - Functors, Applicatives, Monads, Monoids and more.
Home Page: http://fluokitten.uncomplicate.org
License: Eclipse Public License 1.0
(fmap subs {:a "abc" :b "cde"} {:a 1 :c 2})
(fapply {:a (partial subs "abc") :b (partial subs "abc")} {:a 1 :c 2})
(Map Keyword String)
(first parameter is of type (Map Keyword (IFn [Int -> String]))
, second parameter is of type (Map Keyword Int)
, so we fapply (Applicative (IFn [Int -> String]))
to (Applicative Int)
and shall obtain (Applicative String)
(type annotation of typed clojure is used)).{:a "bc" :c 2}
- Heterogeneous map.(fapply {:a inc nil dec} {:a 1 :b 2}) = {:a 2 :b 1}
(fapply {:a inc :c dec} {:a 1 :b 2}) = {:a 2 : b 2}
In fact both fapply and variadic fmap for maps works only in case of maps of identical keys, or functions with variadic homogeneus parameters.
Hey, it would be nice to also have type annotations using core.typed. Have you thought about it?
thx for the project!!
Using 'fmap' as variadic function requires instance of Applicative. Proof: you can define 'fapply' as (partial fmap apply) and '(pure x)' as (fmap #(identity x)) (it is impossible to write this realisation of 'pure' in clojure due to the absence of return-type polymorphism). Looks like this point was discussed in Issue #12 .
Lists and other sequentional collections can be instances of Applicative and Monad in two different ways: as fixed-size vectors with componentwise operations, and as an undetermenistic computation (undetermenistic computation is more common and it is a default behaviour in Haskell):
If variadic 'fmap' and 'fapply' are defined independently, then inequality
(not= (fmap apply [inc dec] [1 2]) (fapply [inc dec] [1 2])) is an unexcpected behaviour from my point of view.
And in the case of sequentional collections (i) is chosen for 'fmap' and (ii) for 'fapply'.
Every Monad has an inherited Applicative Functor structure, but in the library Monad and Applicative protocol realisations for sequential collections are incoherent (see (2)) which is an unexpected behaviour from my point of view.
There should be a macro for helping with chained binds. This macro, mdo should be modeled on Haskell's do, but also take into account how Clojure's let form works. There should be a return implementation available inside the macro, that will be a shortcut to (pure m).
It should look something like this:
(mdo [a
Please support my work on Patreon. I'll intive you to a dedicated Discord discussion server. Can't afford to donate? Ask for a free invite.
Currently, the only difference between the vararg fmap and vararg fapply is that the vararg fmap is (fapply (pure x f) x). That is a bit redundant, and can be shortened, so Functor implementations only need to implement the two-arg fmap, while core.fmap should wrap its f argument with pure and call fapply. This implementation is also more consistent with Haskell's and avoids having to explicitly define functor laws for varargs.
While reading the Fluokitten documentation I noticed that it's often touted as an advantage of implementing these concepts in Haskell that fmap
is able to variadic. Later, it's pointed out Haskell requires using (<*>)
or ap
to achieve this effect.
The problem is that variadic fmap
just isn't fmap
—it's a stronger requirement than just being a Functor. In particular, it imbues a kind of sequencing on your "Functor" which is above the call of duty for just having a Functor—you're opening up each of the boxes in sequence, calling the combining function, then closing them back. A normal functor should disallow that.
One place this distinction shows up is that it prevents you from extracting the commonalities between various applicative instances of Lists/vectors. The applicative instance of vector in Fluokitten is the "Cartesian applicative"
pure a = [a]
fs <*> xs = [f x | f <- fs, x <- xs]
> [(+1), (+2)] <*> [1,2,3]
[2,3,4,3,4,5]
But there's also a law-abiding applicative instance for Lists/vectors of any fixed length. Often this is implemented with infinite lists in Haskell
pure a = repeat a -- [a, a, a, a, ...]
fs <*> xs = zipWith (\f x -> f x) fs xs
> [(+1), (+2)] <*> [1,2,3]
[2,4]
This is all well and good—these are distinct types. However, it's important to note that they both have identical Functor instances so long as fmap
is not variadic.
In fact, in Haskell we have the guarantee that there is exactly one non-pathological function with the type
fmap :: (a -> b) -> (f a -> f b)
and satisfying fmap id = id
. That's the power of the Functor laws.
Obviously, it's a design choice in Fluokitten to include variadic fmap
or not, but it's a patent inaccuracy in the documentation to call an interface Functor
if it provides a variadic fmap
.
Hi, I've been toying around fluokitten and which is very fun. However, I found there're some
inconsistent behaviors between document at Fluokitten Extensions of Clojure Core and the result.
For example;
The doc says
(fmap inc (empty (seq [1]))) => (empty (seq [2]))
(fmap inc (lazy-seq [])) => (lazy-seq [])
However, what I got is
(fmap inc (empty (seq [1]))) => ()
(fmap inc (lazy-seq [])) => ()
Is this correct?
http://fluokitten.uncomplicate.org/articles/clojure_core_extensions.html
Foldable Section
Objects Section
On [org.clojure/clojure "1.8.0"]
and using :uberjar {:aot :all}
I'm using the clojure:onbuild
docker image it runs on openjdk 8 using the openjdk:8-alpine
image and leiningen 2.7.1
Running the jar file causes
Exception in thread "main" java.lang.ExceptionInInitializerError
at java.lang.Class.forName0(java.base@9-internal/Native Method)
at java.lang.Class.forName(java.base@9-internal/Class.java:378)
at clojure.lang.RT.classForName(RT.java:2168)
at clojure.lang.RT.classForName(RT.java:2177)
at clojure.lang.RT.loadClassForName(RT.java:2196)
at clojure.lang.RT.load(RT.java:443)
at clojure.lang.RT.load(RT.java:419)
at clojure.core$load$fn__5677.invoke(core.clj:5893)
at clojure.core$load.invokeStatic(core.clj:5892)
at clojure.core$load.doInvoke(core.clj:5876)
at clojure.lang.RestFn.invoke(RestFn.java:408)
at clojure.core$load_one.invokeStatic(core.clj:5697)
at clojure.core$load_one.invoke(core.clj:5692)
at clojure.core$load_lib$fn__5626.invoke(core.clj:5737)
at clojure.core$load_lib.invokeStatic(core.clj:5736)
at clojure.core$load_lib.doInvoke(core.clj:5717)
at clojure.lang.RestFn.applyTo(RestFn.java:142)
at clojure.core$apply.invokeStatic(core.clj:648)
at clojure.core$load_libs.invokeStatic(core.clj:5774)
at clojure.core$load_libs.doInvoke(core.clj:5758)
at clojure.lang.RestFn.applyTo(RestFn.java:137)
at clojure.core$apply.invokeStatic(core.clj:648)
at clojure.core$require.invokeStatic(core.clj:5796)
at clojure.core$require.doInvoke(core.clj:5796)
at clojure.lang.RestFn.invoke(RestFn.java:408)
at uncomplicate.fluokitten.core$loading__5569__auto____3776.invoke(core.clj:9)
at uncomplicate.fluokitten.core__init.load(Unknown Source)
at uncomplicate.fluokitten.core__init.<clinit>(Unknown Source)
at java.lang.Class.forName0(java.base@9-internal/Native Method)
at java.lang.Class.forName(java.base@9-internal/Class.java:378)
at clojure.lang.RT.classForName(RT.java:2168)
at clojure.lang.RT.classForName(RT.java:2177)
at clojure.lang.RT.loadClassForName(RT.java:2196)
at clojure.lang.RT.load(RT.java:443)
at clojure.lang.RT.load(RT.java:419)
at clojure.core$load$fn__5677.invoke(core.clj:5893)
at clojure.core$load.invokeStatic(core.clj:5892)
at clojure.core$load.doInvoke(core.clj:5876)
at clojure.lang.RestFn.invoke(RestFn.java:408)
at clojure.core$load_one.invokeStatic(core.clj:5697)
at clojure.core$load_one.invoke(core.clj:5692)
at clojure.core$load_lib$fn__5626.invoke(core.clj:5737)
at clojure.core$load_lib.invokeStatic(core.clj:5736)
at clojure.core$load_lib.doInvoke(core.clj:5717)
at clojure.lang.RestFn.applyTo(RestFn.java:142)
at clojure.core$apply.invokeStatic(core.clj:648)
at clojure.core$load_libs.invokeStatic(core.clj:5774)
at clojure.core$load_libs.doInvoke(core.clj:5758)
at clojure.lang.RestFn.applyTo(RestFn.java:137)
at clojure.core$apply.invokeStatic(core.clj:648)
at clojure.core$require.invokeStatic(core.clj:5796)
at clojure.core$require.doInvoke(core.clj:5796)
at clojure.lang.RestFn.invoke(RestFn.java:2088)
at stellar.access.samples.consumer$loading__5569__auto____2873.invoke(consumer.clj:1)
at stellar.access.samples.consumer__init.load(Unknown Source)
at stellar.access.samples.consumer__init.<clinit>(Unknown Source)
at java.lang.Class.forName0(java.base@9-internal/Native Method)
at java.lang.Class.forName(java.base@9-internal/Class.java:378)
at clojure.lang.RT.classForName(RT.java:2168)
at clojure.lang.RT.classForName(RT.java:2177)
at clojure.lang.RT.loadClassForName(RT.java:2196)
at clojure.lang.RT.load(RT.java:443)
at clojure.lang.RT.load(RT.java:419)
at clojure.core$load$fn__5677.invoke(core.clj:5893)
at clojure.core$load.invokeStatic(core.clj:5892)
at clojure.core$load.doInvoke(core.clj:5876)
at clojure.lang.RestFn.invoke(RestFn.java:408)
at clojure.lang.Var.invoke(Var.java:379)
at clojure.lang.Util.loadWithClass(Util.java:250)
at stellar.access.samples.consumer.<clinit>(Unknown Source)
Caused by: java.lang.ClassNotFoundException: clojure.core.reducers.CollFold
at jdk.internal.loader.BuiltinClassLoader.loadClass(java.base@9-internal/BuiltinClassLoader.java:366)
at jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(java.base@9-internal/ClassLoaders.java:184)
at java.lang.ClassLoader.loadClass(java.base@9-internal/ClassLoader.java:419)
at java.lang.Class.forName0(java.base@9-internal/Native Method)
at java.lang.Class.forName(java.base@9-internal/Class.java:378)
at clojure.lang.RT.classForName(RT.java:2168)
at clojure.lang.RT.classForName(RT.java:2177)
at uncomplicate.fluokitten.algo__init.__init2(Unknown Source)
at uncomplicate.fluokitten.algo__init.<clinit>(Unknown Source)
... 70 more
project.clj :
(defproject stellar/access "0.1.0-SNAPSHOT"
:description "Panel Data Collection"
:url "http://example.com/FIXME"
:license {:name "Eclipse Public License"
:url "http://www.eclipse.org/legal/epl-v10.html"}
:dependencies [[org.clojure/clojure "1.8.0"]
[org.clojure/core.async "0.3.443"]
[org.clojure/algo.monads "0.1.6"]
[uncomplicate/fluokitten "0.6.0"]
;--------------------------------Formats
[cheshire "5.7.1"]
[org.clojure/data.csv "0.1.4"]
[semantic-csv "0.2.1-alpha1"]
;--------------------------------Time
[clj-time "0.13.0"]
[jarohen/chime "0.2.2"]
[tick "0.2.4"]
;--------------------------------Technology
[com.novemberain/langohr "3.7.0"]
[com.novemberain/monger "3.1.0"]
[org.slf4j/slf4j-nop "1.7.12"] ;) To stop mongo.java logs
;--------------------------------Loggin-and-Profiling
[com.taoensso/timbre "4.10.0"]
[com.taoensso/tufte "1.1.1"]
;--------------------------------For-Eastwood-Vim-Linter
[jonase/eastwood "0.2.4" :exclusions [org.clojure/clojure]]
;--------------------------------For-Fireplace-??
[cider/cider-nrepl "0.14.0"]
[lein-cljfmt "0.5.6"]
;--------------------------------
[danlentz/clj-uuid "0.1.7"]
[random-seed "1.0.0"]
]
:test-paths ["test"]
:aliases {"itest" ["midje" ":filters" "it"]
"utest" ["midje" ":filters" "-it"]
"test" ["midje"]}
:plugins [[cider/cider-nrepl "0.14.0"]
[venantius/ultra "0.5.1"]
[jonase/eastwood "0.2.4"]
[venantius/yagni "0.1.4"]
[lein-cljfmt "0.5.6"]
[lein-midje "3.2.1"]]
:repl-options {:host "0.0.0.0" :port 34567}
:main nil
:target-path "target/%s"
:jvm-opts ["-Xmx2g" "-Xms512m" "-XX:+UseConcMarkSweepGC"]
:profiles {:uberjar {:aot :all}
:dev {:dependencies [[midje "1.8.3"]
[jonase/eastwood "0.2.4" :exclusions [org.clojure/clojure]]]}})
Hey, I really thing it would be valuable to have a Show protocol
consider de following code
(just {:a 2})
;;#<Just uncomplicate.fluokitten.algo.Just@3c6f0c2b>
(show (just {:a 2}))
;;Just {:a 2}
Thanks again!
(def curried-add4-a (curry add4)) ;; arity 2
(def curried-add4-b (curry add4)) ;; arity 2
(def curried-add4-c (curry add4)) ;; arity 2
(def curried-add4-d (curried-add4-a curried-add4-b curried-add4-c)) ;; arity 4
(def curried-add4-e (curried-add4-a curried-add4-b 5)) ;; arity 3
Does the library supports clojurescript also?
I followed the instructions in Fast Map and Reduce for Primitive Vectors and Matrices to test the performance of neaderthal and fluokitten. What I found are:
For instance,
(def nx (dv (range n)))
(def ny (dv (range n)))
(defn p+ ^double [^double x ^double y] (+ x y))
(defn p* ^double [^double x ^double y] (* x y))
(with-progress-reporting (quick-bench (foldmap p+ 0.0 p* nx ny)))
; Execution time mean : 19.735098 ms
Also, the same tests were performed using the current dev version of fluokitten and it also ended up with much slower execution time than what in the post. I wonder what might be causes of such large discrepancies?
It would be great if someone can also conduct similar tests.
Fluokitten is really cool! I wanted to start by thanking you for your effort.
Is a port to clojurescript at all possible in the future? The reason I ask is because clojurescript desperately needs an async monad to alleviate callback hell...
With version 0.5.1 on clojure version 1.8.0, I encountered this behavior:
(fold (range 99)) => 4851
(fold (range 999)) => 498501
(fold (vec (range 99))) => 4851
(fold (vec (range 999))) => 0
(fold (vec (range 512))) => 130816
(fold (vec (range 513))) => 0
It seems that fold
breaks for vectors with more than 512 elements?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.