I am pleased to announce a first public release of new (and different) "monads and friends" library for Clojure.Extensive documentation is at http://fluokitten.uncomplicate.org
--
--
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clo...@googlegroups.com
Note that posts from new members are moderated - please be patient with your first post.
To unsubscribe from this group, send email to
clojure+u...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
---
You received this message because you are subscribed to the Google Groups "Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email to clojure+u...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.
return a >>= k = k a m >>= return = m m >>= (\x -> k x >>= h) = (m >>= k) >>= h
And in this case you have to explicitly specify which monad you want to use, every time you call bind. I understand that in some case it might be a preferred way, but in my opinion for most cases that I care about I prefer it the other way.
Regarding monadic laws, which one exactly demands that you cannot change the monad (not counting the fact that haskell's implementation does it that way)? Here are the laws, in Haskell:return a >>= k = k a m >>= return = m m >>= (\x -> k x >>= h) = (m >>= k) >>= hIt seems to me the laws are still satisfied if you keep changing monads in each bind (if compiler is not restricting it, as is the case with Haskell but not with Clojure).
On Tue, Jul 2, 2013 at 4:33 PM, Dragan Djuric <drag...@gmail.com> wrote:Regarding monadic laws, which one exactly demands that you cannot change the monad (not counting the fact that haskell's implementation does it that way)? Here are the laws, in Haskell:return a >>= k = k a m >>= return = m m >>= (\x -> k x >>= h) = (m >>= k) >>= hIt seems to me the laws are still satisfied if you keep changing monads in each bind (if compiler is not restricting it, as is the case with Haskell but not with Clojure).I suppose that may be right: you're supposed to verify that the laws obtain for a putative monad; they don't come for free just by calling something a monad. Allowing >>= to have the type m a -> (a -> n b) -> n b just means that you can't verify that yours obeys the laws. If you get to choose the type of "return", even the second one is up for grabs! It does seem somewhat odd to me to advertise the package as being familiar to Haskellers and to employ category-theoretic concepts and then to be so blasé about the definition of a monad. (I wonder if you can get away with this changing of type at all if you define bind in terms of fmap and join).
On Tue, Jul 2, 2013 at 4:33 PM, Dragan Djuric <drag...@gmail.com> wrote:
And in this case you have to explicitly specify which monad you want to use, every time you call bind. I understand that in some case it might be a preferred way, but in my opinion for most cases that I care about I prefer it the other way.No, you don't. You don't have to specify the monad you want to use until you actually want to use it:
--
I probably won't be able to resist to type check it with core.typed at some point.
And enough documentation to satisfy Michael Klishin? I'm impressed :)
I probably won't be able to resist to type check it with core.typed at some point.If you contribute that, or help me baking in (some) non-invasive type checking into Fluokitten, that would be FANTASTIC! I have that in vague long-term plans, but I haven't had time to look at core.typed (I only skimmed through the homepage when it was released).
And enough documentation to satisfy Michael Klishin? I'm impressed :)Thanks :) Actually, one of the main project goals is to make monads (et al) approachable for beginners, and for that, docs and tutorials are the main thing. So, this library really does not make much sense without lots of documentation. I hope to even improve it on that point.
one of the main project goals is to make monads (et al) approachable for beginners, and for that, docs and tutorials are the main thing. So, this library really does not make much sense without lots of documentation. I hope to even improve it on that point.
The site source is in the gh-pages branch in the main source repository on github: https://github.com/uncomplicate/fluokitten/tree/gh-pages
On Wednesday, July 3, 2013 2:06:34 AM UTC+2, Ben wrote:On Tue, Jul 2, 2013 at 4:33 PM, Dragan Djuric <drag...@gmail.com> wrote:
And in this case you have to explicitly specify which monad you want to use, every time you call bind. I understand that in some case it might be a preferred way, but in my opinion for most cases that I care about I prefer it the other way.No, you don't. You don't have to specify the monad you want to use until you actually want to use it:Unless you need to use two or more different monads in that function, in which case I don't see now would you do that at all. And, you have to structure the code a bit awkwardly for clojure, and have to say specifically, I want such and such monad type, and run it with a runner. I'm not saying that that is not good option. Clojure has its features and some compromise has to be made. I just prefer the sort of compromises I made for Fluokitten to the sorts of compromises made by other libraries.
Here is how the laws are specified (and tested) in Fluokitten (writing from the top of my head so please excuse me if I mess up something):(def return (pure [])) ;;This def is to make it more familiar for those who already read this tread, it is not actually in fluokitten tests.(def k (comp return foo bar baz)) ;; note the agnostic return. There are ways in Clojure to change what is it bound for, but I won't go into that here, It does not seem that important to me now. The point is, fluokitten supports it...
(>>= (return a) k)=> (k a)(>>= [1 2 3] return)=> m(>>= [1 2 3] (fn [x] (bind (k x) h)))=> (>>= m k h)So, if monad stays the same, everything is nice and tidy and close enough to Clojure and Haskell.Now, what would happen if monad changes after the bind?
The first law does not constrain itThe second does not too, since it says what happens when you bind with (pure m) not (pure n)The third, associativity, will also be satisfied
However, I think this, regarding the second law, is telling: "The second does not too, since it says what happens when you bind with (pure m) not (pure n)"
*all* the laws only say what happen when you stay within the same monad, because the types the laws give to >>= and return *require* that.
Monads as a Haskell construct is what the previously mentioned laws describe. Monads in category theory are defined in a category X as a triple (T, n, m) where T is a functor and m and n certan natural transformations such that certan diagrams commute. In that sense, I am not sure that even Haskell's implementation is perfectly clean.
Yes, I agree completely, when we stay inside Haskell. However, Clojure is dynamic. Here are two objects that are equal despite having different types:
If you're going to talk about "category theory concepts", then that's the constraint you have to operate under. "monad" is constituted by the laws, the laws involve operations with a certain type, and that's just it. It's not a matter of being in Haskell or not, it's a matter of accurately implementing the concepts you claim to be implementing.
Monads as a Haskell construct is what the previously mentioned laws describe. Monads in category theory are defined in a category X as a triple (T, n, m) where T is a functor and m and n certan natural transformations such that certan diagrams commute. In that sense, I am not sure that even Haskell's implementation is perfectly clean.There's a lot of nitpicking to be done, but, that's not the point, and we are digressing a bit. The point is that in Fluokitten, you are expected to work within the certain monad as you agree, and since there is no type checking on the value that a function returns, it is the responsibility of the developer to make sure that it makes sense as in Clojure generally. It is fairly easy to do by passing a parameter to f that pure can use, if f implementation needs to be agnostic to the actual monad that it will be called from.There are other approaches, so the programmer can make a choice that is the best fit for the problem at hand.Even in the example that you gave from your library, what stops the programmer to shoot himself in the foot by doing basically the same thing that we are talking about here:(defn f [g] (comp atom g g))(require '[monads.maybe :as m])(def mc (>>= (return 3) (f inc)))(run-monad m/m mc)
What is the result if f is broken (in the context of the monad m/m in this case)? I didn't try it, so I may be wrong, but I doubt that the Clojure compiler complains about that one.
New features:
Changes: