Pretty weird that a comment linking a chapter from an oft referred to haskell text is a dead comment here. Surely if the alternate explantion in "Learn You a haskell for great good" is somehow sub-optimal it would be better to explain how rather than kill the comment inside 10 minutes? You see this sort of thing from language warriors fighting silly wars but, yeah, what's wrong with Learn You a Haskell? Why must it b…
It was probably automated. larusso has only made two comments ever, both containing links, so that probably triggered the spam detectors. You can manually resurrect for accidentally dead comments like this by clicking on the comment's time and then clicking "vouch".
Functor, Applicative, and Monad
91–100 of 125 posts
Re: Functor, Applicative, and Monad
#92Earlier quoted context omitted.
> And therefore, it's perfectly acceptable to say "I know how monads work with Maybe and List, but not Reader" Because fundamentally, how a Reader implements bind is in no way related to how Maybe or List implement bind. If this is indeed true, what is the point of learning these "patterns"? From a mechanical understanding of the signature of bind and unit, you'd arrive at more sophisticated signatures, say filterM,…
Your example, filterM has the type filterM :: Applicative m => (a -> m Bool) -> [a] -> m [a] from this I can tell you conclusively what it does: it takes a monadic function that returns a Bool after performing some "action" as well as a list of values; it then performs this action on each element and look at whether the result is True or False; when True, keep it otherwise discard it. Now this is already a lot of inf…
doubleIf :: Applicative m => (a -> m Bool) -> [a] -> m [a]
doubleIf f values = case values of
[] -> pure []
x:xs -> prepend x f x doubleIf f xs
where
prepend :: a -> Bool -> [a] -> [a]
prepend x True xs = x:x:xs
prepend x False xs = x:xsRe: Functor, Applicative, and Monad
#93Earlier quoted context omitted.
This is correct, and in contrast to Haskell, where monads are a core part of the language (they are used in the definition of do-notation and list comprehensions) and currently the mainstream way to do IO.
This is misleading. There's no place in the specification of Haskell that specifically defines monads as part of the language. They aren't a language feature. They are a pattern which happens to be expressible in Haskell, and which is supported by libraries: "Haskell's built in support for monads is split among the standard prelude, which exports the most common monad functions, and the Monad module, which contains l…
Re: Functor, Applicative, and Monad
#94I don't think this article is very useful. It doesn't adequately provide an introduction to OCaml code (or adequately explain what a given code snipped is doing) and yet frequently defers to just code to explain a concept. It's an unrealistic expectation to expect an unfamiliar reader to simultaneously infer what a particular code snippet is doing then also go a level deeper and understand the concept that is trying…
OCaml (Reason) was my entry point into Typed FP (after a few failed attempts at learning Haskell). The best thing about OCaml is that it allows side-effects, so one can go a long way without having to touch advanced FP. It is only recently that I've started getting comfortable with concepts cogently explained in this post, so to me it is quite valuable. As an aside, I think OCaml/Reason/Elm should become the de-facto…
It was a bit of a slog, but there are some wonderful books out there. I don't think we should discount the amount of pedagological resources that are available in the language. My favorite is the "First Principles" book.
As a side effect, I found that once I had learned most of Haskell (minus some of the language extensions aimed at type level programming). You pretty much won't find anything in any other typed language that will surprise you.
Re: Functor, Applicative, and Monad
#95Re: Functor, Applicative, and Monad
#96Earlier quoted context omitted.
Seems similar to type traits in Rust. I skimmed through "Category Theory for Programmers" and it's mentioned this thing is mainly about composition. Composing functions? So you've got a trait (say Functor) that is meant for functions. You know something about functions that have this trait, so you can exploit that knowledge to create compositions of those functions. So then in theory you can write algorithms with as…
Rust traits are pretty much typeclasses. I don't agree with "this thing is mainly about composition" so I don't know what to tell you there. Functor isn't meant for functions, it's meant for types, or rather type constructors (types of kind * -> *). Higher-kinded types are just "what if type parameters could be parameterized types" - I'd argue that from a certain perspective a language that allows them is simpler tha…
Re: Functor, Applicative, and Monad
#97Earlier quoted context omitted.
Your example, filterM has the type filterM :: Applicative m => (a -> m Bool) -> [a] -> m [a] from this I can tell you conclusively what it does: it takes a monadic function that returns a Bool after performing some "action" as well as a list of values; it then performs this action on each element and look at whether the result is True or False; when True, keep it otherwise discard it. Now this is already a lot of inf…
"Conclusively" is probably a little strong. You're relying not just on the type, but also the name - the type alone isn't enough here, even without resorting to bottom, and even when requiring every piece be meaningfully used. For instance, with the same type we can write: doubleIf :: Applicative m => (a -> m Bool) -> [a] -> m [a] doubleIf f values = case values of [] -> pure [] x:xs -> prepend x f x doubleIf f xs wh…
`keep`: Given a predicate and a collection, filter the collection to retain only items for which predicate evaluates to true.
`discard`: Given a predicate and a collection, filter the collection to discard items for which the predicate evaluates to false.
These are two very reasonable functions that would have the exact same signature, would be appropriate for the same arguments, but have two different behaviors!
Re: Functor, Applicative, and Monad
#98I don't think this article is very useful. It doesn't adequately provide an introduction to OCaml code (or adequately explain what a given code snipped is doing) and yet frequently defers to just code to explain a concept. It's an unrealistic expectation to expect an unfamiliar reader to simultaneously infer what a particular code snippet is doing then also go a level deeper and understand the concept that is trying…
Re: Functor, Applicative, and Monad
#99Earlier quoted context omitted.
OCaml (Reason) was my entry point into Typed FP (after a few failed attempts at learning Haskell). The best thing about OCaml is that it allows side-effects, so one can go a long way without having to touch advanced FP. It is only recently that I've started getting comfortable with concepts cogently explained in this post, so to me it is quite valuable. As an aside, I think OCaml/Reason/Elm should become the de-facto…
I learned typed FP from Haskell, coming from JS, and I'm glad I started there. It was a bit of a slog, but there are some wonderful books out there. I don't think we should discount the amount of pedagological resources that are available in the language. My favorite is the "First Principles" book. As a side effect, I found that once I had learned most of Haskell (minus some of the language extensions aimed at type l…
For people from dynamically typed or static OO background, being able to write functional code with records and sum types alone is a huge quality of life improvement. They should be able to get there with the least amount of effort. Haskell however demands far too much understanding and effort before it can be confidently used in a commercial setting. That excludes mainstream programmers who could otherwise most benefit from the paradigm.
Re: Functor, Applicative, and Monad
#100Earlier quoted context omitted.
The point is that Monad, Applicative and Functor are well defined interfaces with laws (properties) you can count on. They are in fact much better, more precisely defined than classic design patterns. And in expressive programming languages (that support higher kinded types or that at least let you encode such types) you can also describe generic code that works over any applicative or monadic type. Having reusable f…
> Having reusable functions that work just as well on lists, maybe/option, reader, io / promise or what have you means these type classes do a very good job at abstracting over data types. These are the purest forms of abstraction. This is where I get kinda lost. Can you give an example of such a reusable function that works for all these things which does something valuable?
http://hackage.haskell.org/package/containers-0.6.2.1/docs/D...
It has the type:
alterF :: (Functor f, Ord k) => (Maybe a -> f (Maybe a)) -> k -> Map k a -> f (Map k a)
Note that it works for all instances of Functor. Trivial choices allow this to reduce to simple things like insert or lookup: insert :: Ord k => k -> a -> Map k a -> Map k a
insert key val map = runIdentity (alterF (\_ -> Identity (Just val)) key map)
lookup :: Ord k => k -> Map k a -> Maybe a
lookup key map = getConst (alterF Const key map)
But those aren't really compelling examples because they just reproduce simpler functionality. It starts to pay off when you start compounding requirements, though. What if you need to insert a value and return the previous one, if it existed? insertAndReturnOld :: Ord k => k -> a -> Map k a -> (Maybe c, Map k a)
insertAndReturnOld key val map = alterF (\old -> (old, Just val)) key map
OK, those are all fine and good, but they're still barely scratching the surface. What if you had problem where when you had a value to insert and there was a previous value at the same key, it was ambiguous which you should use? And let's say the structure of the problem provides interdepencies which restrict the options such that you can't just stack up a list of every possibility for each key. So ideally, you'd like a way to model "insert this value, but if something was already present at this key, give me both possible maps back". Turns out alterF can do that! insertNonDet :: Ord k => k -> a -> Map k a -> [Map k a]
insertNonDet key val map = alterF (maybe [Just val] (\old -> [Just old, Just Val])) key map
Fun facts with that one - thanks to using Functor, it only traverses the tree once, whether it returns one or two results. And thanks to Map being a persistent data type, returning two results only takes O(log n) space more than returning one.(note: this is all typed on my phone without a compiler to verify. There might be simple mistakes in the above, but it's all conceptually sound.)
That's all still just the start. You can insert an IO operation on the old value to calculate the new one, and it still only traverses the data structure once. Or a huge number of other things. Anything that can be made into a Functor can be used to augment the operation alterF does.
And you know the best part of all this? Despite all that freedom, the type of alterF tells you that you can't change the key associated with a value and even that you can't operate on more than one value in the map. It really is nice when simple things give you lots of options, but make it clear what they don't offer.