Talk:Monad (functional programming)/Archive 2
This is an archive of past discussions about Monad (functional programming). Do not edit the contents of this page. If you wish to start a new discussion or revive an old one, please do so on the current talk page. |
Archive 1 | Archive 2 |
External links modified
Hello fellow Wikipedians,
I have just modified one external link on Monad (functional programming). Please take a moment to review my edit. If you have any questions, or need the bot to ignore the links, or the page altogether, please visit this simple FaQ for additional information. I made the following changes:
- Added archive https://web.archive.org/web/20110815101853/http://mvanier.livejournal.com/3917.html to http://mvanier.livejournal.com/3917.html
When you have finished reviewing my changes, you may follow the instructions on the template below to fix any issues with the URLs.
This message was posted before February 2018. After February 2018, "External links modified" talk page sections are no longer generated or monitored by InternetArchiveBot. No special action is required regarding these talk page notices, other than regular verification using the archive tool instructions below. Editors have permission to delete these "External links modified" talk page sections if they want to de-clutter talk pages, but see the RfC before doing mass systematic removals. This message is updated dynamically through the template {{source check}}
(last update: 5 June 2024).
- If you have discovered URLs which were erroneously considered dead by the bot, you can report them with this tool.
- If you found an error with any archives or the URLs themselves, you can fix them with this tool.
Cheers.—InternetArchiveBot (Report bug) 19:46, 5 April 2017 (UTC)
More Haskell and the image in the lead
The structure that defines the input type and how to compose the different actions together is a monad. |
The complex multivalued square and cube root functions may be composed with the "bind" operator "•" so they produce the sixth root function. Here z is a complex number, and the square brackets denote an array. |
@Diego Moya: you wrote about the lead image It doesn't say how the structure correlates to the monad's return and bind operators
. That's true; monads aren't just a concept in Haskell and that diagram represents a monad that's not in Haskell... Now I'm not going to suggest splitting the article into Monad (Haskell), but the lead has to acknowledge that Haskell's operators aren't the definition of a monad, and if the diagram describes a monad without relating it to Haskell it shouldn't be ruled out... Bright☀ 15:05, 9 May 2017 (UTC)
- The bind and return operators are the name of the monad-defining operators in Haskell, but they are not exclusive from Haskell. The section Formal definition defines a monad with a type constructor, unit function and binding operation. The structure in the image should be explained in terms of these mathematical constructs for relating it to monads in functional programming. I reiterate here my concerns that, without a proper explanation, the image looks like an arbitrary selection of mathematical formulas, and it remains unclear how these relate to the topic of the article. How do we know the image represent a monad and not, say, a set, a lattice, or a directed graph? Diego (talk) 15:47, 9 May 2017 (UTC)
How do we know the image represent a monad and not, say, a set, a lattice, or a directed graph?
'cause the description says "The structure that defines the inputs, outputs, and how to compose the different actions together, is a monad." Bright☀ 20:09, 9 May 2017 (UTC)- Well yes, but then we need to trust the editor saying so, and we can't verify it by ourselves. It doesn't improve our understanding of what a monad is. Diego (talk) 05:40, 10 May 2017 (UTC)
- It improves the reader's understanding since it gives a concrete (visual) example of what monads "do". It's not a standalone replacement for the entire article... Let me give you different examples. What the hell is the diagram on the left for? It's just a couple of ellipses and horizontal lines and three arrows. But if you throw in a description, "The bar and ring paradox is an example of the relativity of simultaneity. Both ends of the bar pass through the ring simultaneously in the rest frame of the ring (left), but the ends of the bar pass one after the other in the rest frame of the bar (right)", it becomes an example of the relativity of simultaneity. You can't verify it without the description because it's just a bunch of symbols, but that doesn't mean it doesn't improve the reader's understanding. For all of this, a reader who's never seen an apple can't verify that a photo of an apple is a photo of an apple if it doesn't have a description saying that it's a photo of an apple, accompanied by an article that describes what is an apple.
- Anyway I'm not going to pursue it further. Bright☀ 06:17, 10 May 2017 (UTC)
- The key in that second example is that it contains the sentence "ends of the bar pass through the ring simultaneously in the rest frame of the ring (left), but the ends of the bar pass one after the other in the rest frame of the bar (right)". I.e. it explains the parts of the image in terms ot the topic. I agree it would be useful having a visual example of the monad, but it needs to be explained with a similar sentence detailing the elements in the image. (The current explanation mentions inputs and outputs, but those are not part of the monad). Diego (talk) 06:24, 10 May 2017 (UTC)
- @Diego Moya: I've tried making the structure of the monad explicit, please inspect. Bright☀ 16:51, 11 May 2017 (UTC)
- The key in that second example is that it contains the sentence "ends of the bar pass through the ring simultaneously in the rest frame of the ring (left), but the ends of the bar pass one after the other in the rest frame of the bar (right)". I.e. it explains the parts of the image in terms ot the topic. I agree it would be useful having a visual example of the monad, but it needs to be explained with a similar sentence detailing the elements in the image. (The current explanation mentions inputs and outputs, but those are not part of the monad). Diego (talk) 06:24, 10 May 2017 (UTC)
- Well yes, but then we need to trust the editor saying so, and we can't verify it by ourselves. It doesn't improve our understanding of what a monad is. Diego (talk) 05:40, 10 May 2017 (UTC)
Thanks, that's the kind of detail I was talking about. Something similar to that image could be a good addition to the lede.
I still don't understand how the structure is a monad from that image, though. The binding operation is a binary function that returns one value, though the arrows for bind in the image make it have one input and two outputs. Is this an instance of currying? In the same way, the unit function return takes on parameter, yet the box in the image takes two inputs. Could you make the labelled boxes map to the parameters in the formal definition of the monad? Diego (talk) 07:55, 12 May 2017 (UTC)
- Sorry, I put bind and return instead of map and append... I'll fix it. Bright☀ 16:04, 12 May 2017 (UTC)
- Made the description explicit, but now it's very long. Bright☀ 21:32, 12 May 2017 (UTC)
Expert on functional programming needed
This topic is in need of attention from an expert on the subject. The section or sections that need attention may be noted in a message below. |
An expert with a great, deep, no-nonsense understanding of functional programming in general (not just a particular language-specific expert) is needed to clean up this article from all the Haskell-specific tone, examples and references and make it what its title says it should be, i.e. a true article about monads in functional programming in general.
Reasoning
As many people have noted in this discussion, this article does a poor job explaining what a monad is in the general context of functional programming. It shows what a monad in Haskell is and as such it can be renamed to "Monads in Haskell". But a true article on monads in functional programming in general is needed.
An expert should split out this article into two articles. First should be about monads in Haskell and it may retain most of the original article's content. It will then be up to Haskell experts to clean it up. The second, generic article should be about monads in functional programming in general. It should retain the current title and assume the place of the current page. It should provide a succinct and easy to understand explanation of what a monad is in the general context of funcional programming. It should also explain the motivation behind introducing and using monads in general, before referring to the use cases in any specific programming language.
pbasista (talk) 12:47, 25 July 2017 (UTC)
- @Pbasista:, take into account that articles are written in relation to the available sources, and the majority of sources regarding monads are based on the Haskell language. Do you know a good reference that treats monads in the context of functional programming in general, that we could follow to expand the article in that direction? Diego (talk) 15:29, 25 July 2017 (UTC)
- @Diego Moya: Duly noted. I am not aware of any good resources on monads in functional programming in general and that is why I have suggested that an expert should look into it. There is a related stackoverflow question, which has some answers, e.g. this one, that explain the topic in a programming-language-independent way. Or there is this article, which is Python-specific, but has a section called "Generalisation - Monads" further down, where it uses a generic terminology. So, there are generic resources that are not specific to any functional programming language, but they need to be carefully picked and summarized in this article by an expert. pbasista (talk) 17:21, 25 July 2017 (UTC)
I'm actually looking for a place to stick my non-Haskell example, but the article is so focused on Haskell there's no section where the image and its description could fit. Bright☀ 16:02, 28 July 2017 (UTC)
Archived discussion prior to 2017
I've archived all discussion prior to 2017. It's important to note that many editors pointed out that this article is too Haskell-centric and poorly structured. Bright☀ 17:08, 30 July 2017 (UTC)
External links modified (January 2018)
Hello fellow Wikipedians,
I have just modified 3 external links on Monad (functional programming). Please take a moment to review my edit. If you have any questions, or need the bot to ignore the links, or the page altogether, please visit this simple FaQ for additional information. I made the following changes:
- Added archive https://web.archive.org/web/20080826063940/http://spbhug.folding-maps.org/wiki/MonadsEn to http://spbhug.folding-maps.org/wiki/MonadsEn
- Added archive https://web.archive.org/web/20060720194204/http://moonbase.rydia.net/mental/writings/programming/monads-in-ruby/00introduction.html to http://moonbase.rydia.net/mental/writings/programming/monads-in-ruby/00introduction.html
- Added archive https://web.archive.org/web/20110607225735/http://lamp.epfl.ch/~emir/bqbase/2005/01/20/monad.html to http://lamp.epfl.ch/~emir/bqbase/2005/01/20/monad.html
When you have finished reviewing my changes, you may follow the instructions on the template below to fix any issues with the URLs.
This message was posted before February 2018. After February 2018, "External links modified" talk page sections are no longer generated or monitored by InternetArchiveBot. No special action is required regarding these talk page notices, other than regular verification using the archive tool instructions below. Editors have permission to delete these "External links modified" talk page sections if they want to de-clutter talk pages, but see the RfC before doing mass systematic removals. This message is updated dynamically through the template {{source check}}
(last update: 5 June 2024).
- If you have discovered URLs which were erroneously considered dead by the bot, you can report them with this tool.
- If you found an error with any archives or the URLs themselves, you can fix them with this tool.
Cheers.—InternetArchiveBot (Report bug) 11:36, 21 January 2018 (UTC)
External links modified (February 2018)
Hello fellow Wikipedians,
I have just modified one external link on Monad (functional programming). Please take a moment to review my edit. If you have any questions, or need the bot to ignore the links, or the page altogether, please visit this simple FaQ for additional information. I made the following changes:
- Added archive https://web.archive.org/web/20160223044823/http://docs.scala-lang.org/tutorials/FAQ/yield to http://docs.scala-lang.org/tutorials/FAQ/yield
When you have finished reviewing my changes, you may follow the instructions on the template below to fix any issues with the URLs.
This message was posted before February 2018. After February 2018, "External links modified" talk page sections are no longer generated or monitored by InternetArchiveBot. No special action is required regarding these talk page notices, other than regular verification using the archive tool instructions below. Editors have permission to delete these "External links modified" talk page sections if they want to de-clutter talk pages, but see the RfC before doing mass systematic removals. This message is updated dynamically through the template {{source check}}
(last update: 5 June 2024).
- If you have discovered URLs which were erroneously considered dead by the bot, you can report them with this tool.
- If you found an error with any archives or the URLs themselves, you can fix them with this tool.
Cheers.—InternetArchiveBot (Report bug) 07:16, 4 February 2018 (UTC)
Formal definition before Haskell
As part of the efforts to make this article less Haskell-oriented, I suggest placing the formal definition section first. Additionally, I will use the terms from the formal definition in the sixth root example to make it clear which part is which, particularly the arrows that are easy to miss. Bright☀ 15:00, 24 April 2018 (UTC)
- The image became too crowded with descriptive text next to each element, so I added it in the description instead. It fits well next to the formal definition. Bright☀ 17:11, 24 April 2018 (UTC)
Formal definition should be clarified
The "Formal definition" section presently says that:
- Typically, the binding operation can be understood as having four stages:
-
- The monad-related structure on the first argument is "pierced" to expose any number of values in the underlying type t.
- The given function is applied to all of those values to obtain values of type (M u).
- The monad-related structure on those values is also pierced, exposing values of type u.
- Finally, the monad-related structure is reassembled over all of the results, giving a single value of type (M u).
This doesn't seem to follow from the provided signatures. I suggest this explanation instead:
- The monad-related structure on the first argument is "pierced" to expose the value of the underlying type t.
- The given function is applied to the value to obtain a value of type (M u).
And that's all. Whether the underlying type t is a collection type or not is irrelevant and should be handled by the provided function. If this is not the case, and the structure must indeed be pierced twice, then some explanatory text should be added to explain the importance or utility of this practice. 2001:4200:1010:1078:325A:3AFF:FE7E:3341 (talk) 14:00, 1 August 2018 (UTC)
Page Rewrite (October 2018)
Hi there, I've had this article on my radar for a while, and I hope my changes are for the better. I don't claim to be an expert, but I've studied some category-theory, logic, and language-design so I think I can help help push the article forward some. If anyone decides to revert or has a comment, I'll be keeping an eye on this talk page. So if you leave some feedback here, I'll take it into account going forward.
I plan to move down the article from top to bottom, though I'll give everything a second pass to proofread, maybe change the section organization some too. I also don't plan to mess with the code examples much, if I do at all. For now, my main goals are just to whittle the article down, explain things as clearly as I can without referring to symbols, and spruce up the links and references.
I'd say I've made two major changes so far:
- I cut the "safe division" example because I felt the "Maybe add" function already hit the same points plus some. If everyone wants to bring it back though, I can do that in a different part of the article that flows bet:ter.
- I've also been using the words "unit" and "bind" in bold to discuss the monad operators. I know the goal was to de-Haskellize the article, but I personally wouldn't mind defining Haskell-ish symbols in the overview and using them throughout. However, I do think we should emphasize the name "unit" instead of "return" outside of Haskell examples. "Unit" matches the original category theory, Wadler's early paper, and is more intuitive in my mind, whereas AFAICT "return" is popular only because Haskell uses it to make do-notation look more imperative.
One last point is I've added some references that point to Haskell's wiki and documentation; I figured that isn't a problem as long as we aren't bringing over the language-specific terms or syntax. I could see a non-wiki source being more ideal too, but I figure the official Haskell wiki is relatively authoritative. Zar2gar1 (talk) 21:34, 8 October 2018 (UTC)
- How does a monad differ from a class? -Inowen (nlfte) 06:44, 11 November 2018 (UTC)
- Please see type class. (Haskellers use 'class', which is not the same as the object-oriented class. For them, class is an abbreviation for type class.)
- Mac Lane, Categories for the Working Mathematician: "A monad is a monoid in the category of endofunctors." We can't have that slogan in the article, as it amounts to a distraction, while the article is in process. Can we take this to your talk page, please. --Ancheta Wis (talk | contribs) 11:45, 11 November 2018 (UTC)
- My question was about the novice idea of monads being akin to classes in oop, which is naive but I think its common and thus something to address. -Inowen (nlfte) 12:53, 11 November 2018 (UTC)
- But the novice, by so phrasing, has shown it would have been better to have remained silent until the question has reformulated itself in the mind of the novice. Please see your talk page. --Ancheta Wis (talk | contribs) 16:00, 11 November 2018 (UTC)
@Zar2gar1, The OOP terminology is harming the article. Do you plan to scrub it out? I added a useful citation. The Haskell Wikibook on the State monad is another resource. It may be useful to explicitly state that lists are monads in the lede, to give the reader a concrete example of the parallel between list comprehensions and the wikibook example: rollDie = do generator <- get
feed to patterns from a monad. --Ancheta Wis (talk | contribs) 17:37, 11 November 2018 (UTC)
- @Ancheta Wis: Hi there, I didn't really have specific plans for hints/references to OOP ideas either way. On my first pass, I considered notes on how certain functional ideas might correspond to OOP just because I figure a lot of people come to functional programming from more of an OOP background. I decided they were just distracting though and took them out.
- There are two places I personally see some value in keeping OOP-ish ideas. The first is I kept the "design pattern" part of the lede definition; I couldn't really think of a better way to get across that monads are abstract and not unique to Haskell, or even functional languages, without getting bogged down in category theory. The second is that, IIUC, the generic classes like
Monad
andFunctor
pretty much do work like interfaces in Java. I think it might be counter-productive not to have some links to OOP concepts there, like inheritance and encapsulation.
- Like I mentioned above, my background is more in category theory and logic, and I've studied Haskell and some other functional languages from more of a design perspective. I expect that will color my edits in ways that others can improve on. Also, I only occasionally edit Wikipedia as sort of a hobby when I don't have much else going on (and as warm-up for doing research IRL) so you and all the other editors have my blessing to hack away at anything I've written. You don't have to worry about me taking changes personally or starting any edit wars.
- My only request is if everyone could hold off just a few days more on:
- Changes to specific notation in the examples
- The bottom part of the article
- I'm actually just about to make my last edit on the "Variations" section, and then I should be done with my second pass sometime later this week. After that, I'll take down the Restructure template and explain my notation choices here on the talk page. I would definitely appreciate others working over my changes at that point though. If I have the time and inclination, I might work up a navbox or two to add, but otherwise, I'll be finished. Zar2gar1 (talk) 18:55, 11 November 2018 (UTC)
- @Zar2gar1 Here is a synopsis from a tutorial ala Hudak (2000) p.253 (I include it here because Hudak is out of print. Hudak notes that a Haskell keyword 'do' signals that a monad is at work. Hudak actually chains e1; e2; e3; e4 etc):
{- e1; e2; e3; ... are monadic expressions; p is a pattern returned by e1, which then feeds into e2. e2 yields a new pattern to feed into e3, etc. -} do e1 ; e2 = e1 >> e2 do p <- e1; e2 = e1 >>= \p -> e2
- The above is the gist of Hudak. To me, the sequence e1; e2; e3; e4; ... explains why monads are 'programmable semicolons'. If the pattern p fails, the monad might simply select a new behavior from the next expression feeding from p into e2; e3; etc.. That is why I am so cautious about 'typeclass'. Each typeclass is for a different behavior. 'fail' or 'error' might well be inappropriate behavior, depending on the application. A 'lift' might be what is needed, when an appropriate pattern surfaces. --Ancheta Wis (talk | contribs) 07:21, 12 November 2018 (UTC)
- @Ancheta Wis: So first off, since both you and Diego explicitly mentioned moving some mention of
List
back into the lede, I'm going to do that (along withMaybe
). I'm going to hold off on any specific examples or further explanations in the lede though, for the reasons I gave in my reply to Diego. But if you and the other editors come to an agreement on adding it in, I don't see a problem.
- @Ancheta Wis: So first off, since both you and Diego explicitly mentioned moving some mention of
- As for the Hudak reference, it's a good find and can probably work in several spots, but I don't know if it precludes us from mentioning type classes in the article. Reading the parts you quoted in context, I get the impression he's not saying that each monadic expression can have wildly different behavior (though I guess they could if you're using the
Continuation
monad). Instead, I think he's trying to explain the syntax and laws of monads without actually defining one. To have a working monad, you would have to define the specifics of the required operators, which imposes a unique behavor (corresponding as you said to a unique type class).
- As for the Hudak reference, it's a good find and can probably work in several spots, but I don't know if it precludes us from mentioning type classes in the article. Reading the parts you quoted in context, I get the impression he's not saying that each monadic expression can have wildly different behavior (though I guess they could if you're using the
- It's been a while since I studied Haskell in detail, but I vaguely remember "pattern matching" meaning something more central to the compiler in Haskell too, almost like a syntax-based variation on type checking. I could be wrong (plus I think more recent versions of Haskell don't have the same
fail
function), but I think the idea is thatfail
was a default exception that the compiler would throw if it caught a type mismatch in a monadic chain. Like you said, that might not be ideal so you could always define your own customfail
, but at that point, you would essentially be deriving/building a new monad (with a new type class). Zar2gar1 (talk) 22:47, 12 November 2018 (UTC)
- It's been a while since I studied Haskell in detail, but I vaguely remember "pattern matching" meaning something more central to the compiler in Haskell too, almost like a syntax-based variation on type checking. I could be wrong (plus I think more recent versions of Haskell don't have the same
@Ancheta Wis who dislikes treating common novice ideas; for you I coin the word "expertine." The novice idea of a monad is something like a class, and then writing about the difference is useful. -Inowen (nlfte) 19:36, 11 November 2018 (UTC)
Lede section
@Zar2gar1: I've worked extensively on the previous lede section, and I'd want to negotiate putting the essence of my contributions back in the article. I believe it is essential that, for a highly abstract topic like this, the introduction contains as much concrete concepts as possible. My concern is that sentences like "a monad generically transforms underlying data types into richer types with some standard higher-order functions (also called "functionals") that must obey formal rules", don't really explain anything to anyone who doesn't already know and understand all those difficult concepts, which require a big deal of knowledge about functional programming and/or formal systems.
I kept adding to and rewriting the section with the target audience of a developer with ample experience in imperative programming in industry, and who is trying to learn about pure functional programming for the first time (probably by researching what Haskell is about, and being told that Monads is the way that side-effects and state are handled). That's the profile of people I've met which is more confounded by monads, and who would benefit from a generic introduction not placed in the context of a FP course. That audience would benefit of noting concrete examples such as the Maybe and List monads, mentioning the bind and unit operators used to define the monads, and explaining as early as possible terms like "monadic variable/value"; as well as showing actual working code using monads, which the "safe division" provided at the start of the Overview section.
I feel that the new lede section does not say anything about the structure of the monad, barely anything about how they are used in a program, or practical reasons why you'd want to use them. For the sentences that appear explained in both versions (chaining functions in a pipeline, supporting referential transparency...) , probably we should use the more concise wording in your version. But I really think that we should also include all the other concepts that were present in the older version, and which helped put the concept in the context of programming at large, not exclusively with respect to functional programming as it is now. Diego (talk) 16:27, 12 November 2018 (UTC)
- @Diego: I'm glad to hear from you because I've noticed you have seniority on this article. I would be fine meeting somewhere in the middle on the section, and with your feedback, I see a few changes I can make that we would probably agree on. Beyond that though, I'll just try to explain my approach, starting with the general points:
- Perhaps my main goal was just to whittle the size down some, per MOS:LEADLENGTH. If you look at my changes to the Overview closely, you may have noticed that I actually just moved a lot of the details from the lead further down (like the list of applications).
- That said, I don't see any problem with fattening up the 3rd paragraph, or even bumping the lead back up to 4 paragraphs and moving some central points back in.
- In particular, a short sentence that previews
Maybe
andList
, and another acknowledging category theory would both be good additions. I just prioritized cutting the length over keeping those things in the lead.
- Another way our versions differ is that I tried to avoid any assumptions of imperative or OOP background in the lead. Now, in retrospect, I probably went too far the other way and over-linked to FP concepts (I'll make another pass to try fixing that). I have more to say below, but I think the ideal for the lead is to avoid both and aim for the simplest English and programming concepts possible.
- You're probably right that the vast majority of readers that come to the article do have programming experience. Even then though, I think moving details geared towards that audience into the Overview or other relevant sections is a small price to pay for keeping the lead as accessible as possible.
- Like I mentioned above, I'm personally for short hints and links to concepts from other paradigms as long as they pop up naturally. I'm just not sure that's really possible in the lead.
- The "programmable semicolon" idea is nice because it can fit in a single clean sentence, but it seems that without a disclaimer right next to it, a lot of readers fall into the trap of thinking monads order operations.
- I also removed the reference to the "assembly line" metaphor because (although I think it's one of the better metaphors because it brings the intuition of "automating" things) it still has a strong "monads order operations" flavor. Also, while I'm normally very fond of metaphors, I'm hesitant to keep any in the article because of the "monad tutorial fallacy" and people's tendency to form subjective opinions about which metaphors are better (like I just did a sentence ago). I really think the only way to win the monad metaphor game is not to play.
- On the safe-division example, I think it's a good code-snippet and kept the F# version in the do-notation section, but I felt the Haskell version at the top sort of distracted from the more fleshed-out example that used add.
- Otherwise, I thought the
Maybe
example belonged at the close of the Overview. I do think mentioning the three monad components first helps motivate the example, but otherwise, it was mostly a stylistic choice. If the consensus is to move it to the top of the Overview, I don't see a problem with that, especially if we can somehow distill the conceptual definition into the lead.
- Otherwise, I thought the
- Perhaps my main goal was just to whittle the size down some, per MOS:LEADLENGTH. If you look at my changes to the Overview closely, you may have noticed that I actually just moved a lot of the details from the lead further down (like the list of applications).
- So those are the issues I have a clear opinion on, but how to address the technical FP concepts in the lead? I'm honestly more ambivalent about that, and I know my edits can be improved upon in that regard. Since the guidance is to avoid uncommon terms when possible, then provide context and wikilink when they're unavoidable, my approach was to take the bull by the horns, link to the FP concepts I felt were central to the article (like referential transparency), then try to smooth them away into simpler terms. After thinking about it, even though it's really hard for an idea like monads, I think the goal should be to strive for even more plain English in the lead, not to bring the technical stuff to the top or piggy-back off of other programming concepts.
- I'm glad you brought up my one sentence too because I'll agree it's definitely stilted and not plain-spoken enough, but in retrospect, what I was trying to do with that sentence hints at what might be a way forward. For monads, it just might not be possible to affirmatively explain the concept without details and exposition that really don't belong in the lead. What we could do though is try to delimit the concept as much as possible by hinting at related concepts and carefully choosing intuitive terms to nudge the reader away from the usual fallacies.
- So in that one sentence you quoted, without ever mentioning them, I was trying to convey the inutition of parametric polymorphism ("generically") via a functor ("a monad... transforms types") with additional structure ("richer types with some standard higher-order functions..."). That last bit in particular is still too stodgy now that I re-read it, but I stand by the idea of trying to hint at the main points without ever mentioning them.
- So those are my pretty much my thoughts on the matter. Besides quick summaries of the history, examples, and use-cases, I think the main goal for the lead should be, with as little technical language as possible, to plant a few main intuitions in the reader's head:
- Monads are not specific to a language or a framework
- They rely on
parametric polymorphism, not ad-hoc polymorphism, subtyping, overloading, etc.bounded polymorphism, not overloading concrete types - They allow modeling computations, not just pure functions
- They actually reify the computations and are referentially transparent
- A monad encapsulates bookkeeping code around ordered computations; it doesn't order the computations itself
- They are not passive things attached to types, but functors with added structure that act on types
- I want to finish my 2nd pass over the bottom of the article first, but then I'll definitely work over the lead again, incorporating this discussion. After that, I can accept whatever everyone else decides going forward. Zar2gar1 (talk) 21:54, 12 November 2018 (UTC)
Haskell
Zar2gar1 you are doing a giant disservice to the article by focusing it around Haskell instead of the general concept of a monad. There has been years of discussion about making this article less Haskell-centric and here you go making it completely focused on Haskell. Bright☀ 12:51, 14 November 2018 (UTC)
- I would go as far as undoing all your changes since you're just making this article a Haskell textbook. Bright☀ 12:54, 14 November 2018 (UTC)
- Phrases like
First, assume a...
orIf this seems like unnecessary hair-splitting
orwe will first pin down...
and a general style of addressing the topic as a textbook or lecture supplement is against Wikipedia policy. Bright☀ 13:01, 14 November 2018 (UTC)- The issues and motivation for using specific languages such as F# and Haskell are discussed above. I think it is clear that the section above is a roadmap. The concepts under discussion are abstract, and a specific language is not the point. Once the concepts are clear and concrete enough to the readership, then we can lift up the text. The similarity to mathematical notation ought to persuade the readership, but we are on a waypoint on a path, to the stated goal of freeing the content from specific syntax. --Ancheta Wis (talk | contribs) 16:38, 14 November 2018 (UTC)
- @BrightR: I'm sorry you feel that way, but I'm not really clear on how I've made the article more Haskell-centric. I've tried to move specific mentions of Haskell (outside the do-notation and IO examples) to either the History section or explanatory notes. I've also been trying to convert all definitions and the main examples to pseudocode; since it's about an inherently functional concept, I think a functional pseudocode would be better than pure mathematics (and trying to shoehorn in too much imperative pseudocode would get messy real quick). There's really no guidance for that though so I've had to put it together as I go along. I plan to summarize all my style choices for the pseudocode here on the talk page once I finish later this week, then let everyone change it as they will.
- As for the diagram, it's a really good flowchart for picturing how the
List
monad can work, but I think it does have some issues. First, I moved it towards the bottom of the section because that's where theList
example is discussed specifically. Also, the very last paragraph of theList
subsection now describes the specific example drawn in the diagram, which cuts down on the image's caption and places it in context within the article.
- As for the diagram, it's a really good flowchart for picturing how the
- On a more technical level, I'm worried that in the form you've reverted to, the diagram's list doesn't qualify as a monad. The way I interpret it, it's saying that acts on the list to break it apart, is applied freely to each value, then is used to stitch the two result lists together (so the end result is correct). though doesn't act on the functor (the list in this case), but is actually part of the functor that acts on morphisms / plain functions ( here). So while the ultimate idea is right, having it act on the list directly and separating out the values might mislead some readers; it also leaves open the possibility of applying different functions to the two intermediate results, which IIUC the monad would disallow.
- Including is also a problem because while it makes
List
a monoid, it's distinct from which flattens nested lists and is the other necessary transformation. If you go back to the problem & solution in the source blog-post, you'll notice that he's using the Haskell functionconcat
, which is actually different from a normal append and concatenates "elements of a container of lists" (i.e. nested lists): concat's specification within the Haskell prelude.
- Including is also a problem because while it makes
- For lists, it's probably not a big deal, but for other monads (especially ones without an operator) it's a necessary distinction. We already discuss earlier so I feel it's more informative to give a pseudocode implementation for in the text, then refer to that in the diagram. Now, if the
>>=
operator bothered you in my version, I see the value of keeping operators out of the diagram and can take it out. I was going to spruce up the image one more time too, aligning the elements and using actual text for the labels (didn't realize at first that Wikimedia prefers not converting text to paths).
- For lists, it's probably not a big deal, but for other monads (especially ones without an operator) it's a necessary distinction. We already discuss earlier so I feel it's more informative to give a pseudocode implementation for in the text, then refer to that in the diagram. Now, if the
- One other thing I'll agree with 100% is that I added some sentences with a conversational tone and the academic "we" in my first draft, and after a re-read, they did seem out of place. At first, my thinking was that it's common in research papers and expositions of technical ideas so it might be more appropriate here than, say, a culture article. I actually tried to clean some of it out on my 2nd pass but I'll keep an eye out for it when I skim the article one last time. For the overall flow of the article though, while I agree the sections should be topical as possible, I think the difficulty of the subject matter justifies a little bit of "walking through" the ideas with the reader. Zar2gar1 (talk) 22:28, 14 November 2018 (UTC)
- Since you are trying to improve the article more than anyone in the past few years, here are some more considerations, other than not focusing on Haskell and not turning the article into a tutorial or textbook:
- Get rid of the notes section. Information like
monads as described in this article are technically what category theorists would call "strong monads"
and the rest of the notes do not belong in a footnote, they belong in the body of the text. - Don't cut out explanations. "This is a list monad" is not an explanation. In particular if you take away all mentions of ° then half of the explanation disappears.
- Don't alter the terms used in the references. If the reference uses "map" and "append", don't use different terms.
- Use references....
- Get rid of the notes section. Information like
- Doing something to the article is a good start, but turning it into a tutorial or textbook is wrong. Bright☀ Bright☀ 15:17, 15 November 2018 (UTC)
- Regarding "append/concat", the reference doesn't use Haskell concat, it uses the colloquial term "concat" in place of the list append function; see concatenation versus append, particularly the hatnot on the concat article. Bright☀ 15:11, 15 November 2018 (UTC)
- Since you are trying to improve the article more than anyone in the past few years, here are some more considerations, other than not focusing on Haskell and not turning the article into a tutorial or textbook:
- One other thing I'll agree with 100% is that I added some sentences with a conversational tone and the academic "we" in my first draft, and after a re-read, they did seem out of place. At first, my thinking was that it's common in research papers and expositions of technical ideas so it might be more appropriate here than, say, a culture article. I actually tried to clean some of it out on my 2nd pass but I'll keep an eye out for it when I skim the article one last time. For the overall flow of the article though, while I agree the sections should be topical as possible, I think the difficulty of the subject matter justifies a little bit of "walking through" the ideas with the reader. Zar2gar1 (talk) 22:28, 14 November 2018 (UTC)
Haskell and the flowchart
@BrightR, I have made the "Notes" section much larger, but I personally think footnotes are a great way to still provide technical details or specifics that might overload the average reader. If everyone agrees to undo that, I can accept it. You're absolutely right about using references too, and I have actually been collecting references as I write. It's just always been a personal preference of mine to first get all the ideas down, then go back over to add the citations, but I'll be working on that today.
I honestly still don't understand some of your criticisms though, like how I've made the article more focused on Haskell. You are right about the need to eliminate the conversational tone, but I don't think walking the reader through some examples or having later sections build on concepts in earlier ones makes the article a tutorial, especially for such a technical subject.
As for the flowchart, I really do like it in the article, and I respect the work you've put into it. After looking a little closer, I think I better understand what you're conveying with it too, but I'd still recommend tweaking it once more. For example, the diagram defines "•" as the bind operator and lift as "unit•f", but if you look in the blog post, the author uses "*" for bind and defines lift with "unit . f", which is simple function composition.
Also, I'll just register my concern one more time that when he uses "concat", he's referring to the Haskell function and simply appending lists wouldn't give you a well-defined bind. One more bit of evidence for that is that in his first example (implementing the Writer
monad), he specifically says the following:
bind must serve two purposes: it must (1) apply f' to the correct part of g' x and (2) concatenate [my emphasis] the string returned by g' with the string returned by f'.
The solution immediately after that, however, doesn't use "concat" but the ++ operator. You might say he does that since ++ is just for string concatenation (though the author makes it pretty clear he's writing with Haskell in mind, where ++ is a more general concatenation). Then the question is though, if the author is distinguishing between concatenation for strings and appending for lists, why didn't he just use the word "append" in the list example to begin with?
Going deeper though (and I guess this shows the difficulty with just following sources in technical articles), I'm still not sure the blog post itself is entirely correct. It's a really good exposition, but if you look at the comments, many people pointed out typos and small errors so I think it has to be used carefully. I'll simply ask this: if "sqrt" and "cbrt" have to be lifted before going into the monad, what would the plain, unlifted versions of those functions look like?
I really don't mean to step on any toes, and I like seeing the flowchart in the article (I'd personally like to see even more diagrams). I just want to make sure it doesn't have subtle errors, and if it turns out to be fine, I'll apologize for so much nitpicking. Zar2gar1 (talk) 16:04, 18 November 2018 (UTC)
Trinot ∘ operator
There is a trinot(mp) = mp >>= (eta ∘ not(p))
pseudocode statement with a '∘' operator which is suggestive of composition, but I'm not sure. Since eta was defined with a parenthesized argument, does eta consume a 'tri-state' value peerhaps, or a monadic value? I ask since if x were a Nothing then Just (x+y) would appear to be ill-formed. Another way to ask this might be 'how would an eta( Maybe T) work?'. If the definition were for a monadic eta( Maybe T), I can see how the result could be Nothing. But not(p) could be Unknown, for a three-valued logic. Trinot might not short-circuit-evaluate to Nothing, and a fail could be the result for some definitions, as given farther down in the article. If I worry needlessly, I would welcome the reassurance. --Ancheta Wis (talk | contribs) 17:48, 20 November 2018 (UTC)
- @Ancheta Wis, sure thing. I'm glad people are willing to check my edits.
- You're right that ∘ is intended as a run-of-the-mill, composition dot. I think the function is ok because the bind operator itself should act like a firewall and process undefined values so the other functions never actually see them. It can be checked by substitution; without getting bogged down in explicit variable binding (though looking at it now, I need to tweak the parentheses to follow my own convention), it should work something like:
mp >>= (eta ∘ not) p ⇔ if mp is Just p then # Apply function only if value is defined (eta ∘ not) p else # Short-circuit otherwise Nothing
- As for whether normal composition is justified, the output for
not
and input foreta
should match up, and the overall input and output should conform to the proper signatureT → M U
(including possiblyT → M T
):
not(p) : Boolean → Boolean eta(x) : T → Maybe T (eta ∘ not) p : Boolean → Boolean → Maybe Boolean
- Now you're right that if you tried cramming a Maybe value into
eta
directly, it would be malformed (and a strictly-typed language should throw an error). The one sort of tricky thing is that you could theoretically useeta
(and unit in general) to repeatedly wrap a monadic value if you used map to lift it to the proper level first. Otherwise though, my understanding is that unit's type signature specifically requires a non-monadic value as input (and I'm much fuzzier on this, but I think even with monad transformers, each monad's level of nesting is sort of kept in a separate bucket).
- More generally, I have finally settled on conventions for the composition dot and how to write function application, and I'll explain those once I'm done editing the article body. Zar2gar1 (talk) 22:59, 20 November 2018 (UTC)
RfC: Being Clear on "Classes"
After a little more thought about the discussion between Inowen and Ancheta Wis, I realized how unavoidable yet tricky the term "class" could be in this article.
In my edits, unless the context implies otherwise, I haven't really been using it with Haskell type classes or OOP classes in mind. I've been using the term in the mathematical sense, as in an absolute collection of things that isn't necessarily a set: Class (set theory). I don't really have a solution in mind beyond setting a standard sense in the lede with a wikilink, then making it clearer whenever the term is used differently. We should probably come to an agreement here though on what the standard sense in the article should be. Zar2gar1 (talk) 19:47, 11 November 2018 (UTC)
- In my novice understanding the monad is like a class in that it is like a functional reuseable object. The understanding I have is that the differences go all the way down to the type of language object oriented or functional, and that makes it difficult for experts to draw comparisons without teaching about the fundamental differences between language forms. In whatever comparison, the key is to explain why they are different. -Inowen (nlfte) 01:08, 12 November 2018 (UTC)
- @Inowen: Hmm, I'm not sure I entirely understand. When you say "the monad is like a class in that it is like a functional reuseable object," are you taking that as a definition? I think that might be problematic for several reasons; for one, that would imply that every function (and maybe even every constant value) is its own class, which at best, would only fit the usual senses of the word very trivially.
- As I understand it, at least for this article, there are really three uses of "class" that might come into play:
- Type class is the Haskell-specific term for the sort of language feature that is typically used to implement monads. The most language- and paradigm-neutral term I've found for the feature is Concept (generic programming), but IIUC, Java's "generics" and C++ "templates" are (roughly) the same thing.
- Class (set theory) is the more mathematical idea, but it's not too complicated. To put it very loosely, you might say a class in set-theory is just a collection of things that's defined "top-down" whereas a set is inherently more "bottom-up". Don't take this as officially, rigorously true, but you could say a class in mathematics is a lot like a (non-enumerated) type in programming.
- Class (computer programming), which is about the OOP notion, isn't really the same because it's inherently constructive, not generic. Concrete OOP classes include actual definitions linked to specific types, but even abstract OOP classes only achieve ad hoc polymorphism. That's why it's important that the article doesn't leave anyone with the impression that monads form a class in this sense, individually or collectively.
- As I understand it, at least for this article, there are really three uses of "class" that might come into play:
- As you can see, all three of those senses have their own articles and are pretty standard in their respective fields. In FP, you can implement a monad using a type class, and mathematically you can talk about the class of all monads (and sub/super-class relationships, like "monads are a subclass of functors"). Funny enough, you can even say that a specific monad induces classes of endofunctors... unless I'm getting mixed up (plus it's completely unnecessary for this article). Anyways, one has to use terminology carefully, but I don't think there's any significant, deeper relationship between the two things. It's just important that we make it clear, explicitly or by context, what we mean when we use the term in the article. Zar2gar1 (talk) 22:21, 12 November 2018 (UTC)
Going forward (Nov/Dec 2018)
Finally! It took much longer than expected, but the rewrite's finished. I tried to take everybody's comments into account and hope it's a net improvement. I've honestly sort of drained my writing battery for now, but I plan to keep an eye on the Talk page for a bit and will happily drop by for small requests or partial reversions if nobody else has the time.
I feel a lot of my choices should speak for themselves and have commented on a few already. There are several last thoughts I made notes of while writing though, and since it's a bit long, I've broken the comments into subsections; hopefully that isn't too taboo. Zar2gar1 (talk) 22:30, 29 November 2018 (UTC)
Last examples
It looks like I skipped the last few monads (Reader
, State
, and Continuation
), but I actually did do some work on those. Instead of editing the article though, my proposed changes are in a draft on my user page: User:Zar2gar1/Monad table draft
I thought it made sense to condense all three into one subsection, then add details into tables. I started hesitating though and thinking it looks like too much of a data dump, but the main reason for not just adding it is simply that the Continuation
monad bested me. I get what continuations are, how they work in simple arrangements, and what the more advanced procedures are doing conceptually.
From when I first studied it in Lisp though, call/cc honestly always seemed like witchcraft to me, and apparently it still goes right over my head. Anyways, I do think in their current form, with just brief descriptions and type signatures, these examples are still teasers, but I'm really not sure my version is any better, especially with the gaps. So what does everybody think? Zar2gar1 (talk) 22:30, 29 November 2018 (UTC)
- There is a theory behind continuations, fortunately. To my knowledge, oleg-at-okmij (Oleg Kiselyov) is the Principal Investigator in the related fields at this time. --Ancheta Wis (talk | contribs) 15:49, 27 December 2018 (UTC)
- Yes, I think we may actually cite him in the article at a couple points already. IIUC, he actually works more on delimited continuations and zippers, but his site is definitely a good resource, and not just for this page.
- As for finishing the table / redoing the section, my main problem isn't so much a lack of sources as it's simply on the edge of what I understand. I know I could finish it if I put in the time to study continuations more in-depth (and I would like to someday), but I just can't guarantee that will happen anytime soon.
- Just to check though, do you like the idea of the table? Or should we stick closer to the current arrangement? I also put a request for expert assistance above the draft on my page, but I don't know if it registers with the WikiProject from User space. If it would help, I could move the request here onto the talk page or try personally asking real quick on the WikiProject page. Zar2gar1 (talk) 19:01, 30 December 2018 (UTC)
Style and pseudocode
Overall, being an FP article, I decided to keep definitions equational and use arrows to represent functions, so it does look vaguely similar to Haskell (though Haskell arguably just does that to look like math). I tried really hard though to avoid (outside of the footnotes) any previous knowledge of...
- Currying, which I replaced with listed parameters.
- Lambda calculus, particularly for binding variables within the monadic chain. I tried to mimic mathematical function application and let context explain the rest instead.
- Sophisticated category theory (like adjunction.
As for wrapping/unwrapping the monadic type, I settled on Hungarian notation of all things. I know it's usually treated like the Nickelback of programming style (no offense if you like Nickelback), but this is one case where it just works.
There is a specific line I couldn't come up with a good style for though: the associative law for comonadic extend. The right-arrows in the monadic version may abuse notation slightly, but I feel they get across how the variables are being bound without complicating things. Unlike bind though, extend intuitively "connects" the terms first, then "rewraps" the result. In the end, I settled on the kludge to put both the operator and the right term in parentheses to emphasize that rewrapping comes 2nd, but I'm really not happy with it. It's like the application in lambda-calculus I tried to avoid, only more confusing because its implicit and backwards. I had some other ideas (like a "split" operator), but they would be extremely non-standard so I'm stuck and open to a different approach for extend.
Otherwise, everything came down to (or trying to) establish patterns and conventions that emphasize important distinctions:
- Features defined for all monads/functors/etc. in general are cursive in prose (using
<math> tags{{mvar}} templates), all other specific names and functions are wrapped in <code>. - Lower-case letters are used to represent things, upper-case letters for types.
- Variables are mostly represented with x,y,z (I wasn't as consistent on this one and let a few exceptions slip through)...
- In particular, p stands for "proposition" in the
trinot
function of theMaybe
example. - Values that are instantiated by assumption and passed down the chain to functions typicaly use a,b,c.
- In particular, p stands for "proposition" in the
- Since monadic functions of type
T → M U
are the most common in the article, f,g,h are used to refer to them exclusively. - In the few instances where they're discussed, non-monadic functions use greek letters φ,χ,κ to represent them (most of these cases only pop up in the last examples)...
- φ is for functions with distinct input and output types. Honestly, φ is just what I'm used to seeing in algebraic proofs for morphisms, plus it's how you transcribe f in Greek.
- χ is for a function that outputs the same type; it comes after φ and transcribes to "ch" in English (different sound, but if you're being charitable, you could say "ch" stands for "change").
- κ is for the
(a → r)
continuations used in that monad.
- The composition dot ∘ works as in mathematics. It feeds one function's output to the next's input, but it cannot be used to apply a higher-order function to its parameter.
- Like in mathematical notation, when an isolated function is applied to variables/values, parentheses are used, but when a compound function is applied, the compound is wrapped in parentheses (like
(f ∘ g) x
).- To avoid confusion, only a space separates a higher-order function from its parameter.
That should pretty much sum up the pseudocode, but again, I really have no personal attachment to any of these choices. If anything, I hope they're just a good start for others to build on. Zar2gar1 (talk) 22:30, 29 November 2018 (UTC)
- Sorry for reverting your pseudocode. It claimed to be Haskell, so I made it so, but I should instead have just removed references to Haskell, which is what I've done now. There were also a few errors such as referring to Just T as a type: in fact Just X, where X is of type T, is a value of type Maybe T, and "Just T" confuses the value and type levels. I've fixed these. Hairy Dude (talk) 16:50, 30 June 2019 (UTC)
- @Hairy Dude: No worries, there were actually a decent amount of changes even within a few months after I finished my edits in 2018. Describing the opening example as Haskell must have been added later. I'm more of a nomadic wiki-editor that likes to overhaul articles so I don't really stick around for repeated changes, but I saw your ping.
- Plus while I personally don't know about some of the section additions & changes since then, I like most of the specific corrections & changes. I do wish the editor that put lambda-expressions back in had discussed it a little since I specifically gave my reason here for leaving them implicit (or using math-ish "f(x = a)" statements when variable binding needs to be explicit). I get where they're coming from too though so if readers generally prefer the lambdas, I'll consider it an improvement.
- Now, there were several things I had in mind but were beyond my skill or time-investment; a much more focused list than all the debriefing notes I plastered this talk-page with. If you do return to edit this article regularly, feel free to tag me in a new talk discussion or section. Zar2gar1 (talk) 19:27, 6 July 2020 (UTC)
Proving the monad laws
I felt a quick demonstration of how to check the monad laws actually adds a lot to the article. It's very important from a theoretical standpoint, but most sources outside research papers skip over it.
That said, I'm not sure the approach I took to actually typing it up is optimal. I felt alignment was really important to keeping the proof clear, but in the end, the only way I could find to do that reasonably within a pseudocode box was very hackish (using HTML comment tags to insert padding). Doing it with LaTeX in a math box might be a lot simpler to align, but I wasn't sure if a block of math formatting would be off-putting for this article.
Does anyone else have experience with a similar situation? Zar2gar1 (talk) 22:30, 29 November 2018 (UTC)
Diagrams and pictures
Although (or because?) the subject is pretty dry, adding a few more images and a little more color to the article might be a quick improvement. I know it's purely aesthetic, but I always like when a page has a little eye-candy (silly as it sounds, I sort of miss how the examples were colored when given in Haskell).
One thing that comes to mind is including a couple screenshots from the programs listed in the Applications section, but a couple more diagrams might not hurt either. Zar2gar1 (talk) 22:30, 29 November 2018 (UTC)
Ideas for navboxes?
Since editing the article took more time and energy than expected, I won't be building some templates I had in mind. I was surprised though that there doesn't appear to be a "Functional programming" navbox (or an OOP one for that matter).
Maybe even more important though, I feel like a big part of understanding monads comes down to seeing how they relate to other concepts like functors. A more structured navbox, or maybe even something like this (though obviously simpler and with different relations) might really add to this and other articles. If it's done right, maybe it could even be useful for some category-theory articles.
I was also wondering if a good infobox for this article is possible and what that might look like. In the end, I kept coming back to the "design pattern" notion from the first sentence; it might be controversial at first since it would mix FP articles with a lot of OOP ones, but it would also make sense for articles like MapReduce. Zar2gar1 (talk) 22:30, 29 November 2018 (UTC)
A radical proposal for bind
While working on parts of the definition, a heretical idea popped into my head. I'm not really for or against it, but since we're trying to move away from relying on any particular language, what if we just used monadic composition (>=> in the Haskell sources, Kleisli arrows in math) for the default definition, and discussed bind as a technicality?
It's explained in most of the main sources, it avoids the weird traps with associativity and variable binding, and it arguably makes the connection back to category theory clearer. The only complication I could see is feeding values along the chain, but maybe even an explicit, pseudocode "input" function could take care of that. So for example, the monadic add
from the top example would change from...
mx >>= (my >>= Just(x + y))
... to something more like...
(input >=> Just (x + y)) (mx,my)
Just a thought. Zar2gar1 (talk) 22:30, 29 November 2018 (UTC)
Dehaskellized example
Hello all, I have added yet another example to the "More Examples" section. See the edit here. (There are a couple other later minor edits for things like word order and periods.)
I would like to nominate this example to be instantiated as the "Overview" example, because I made it because I think it is one of the simplest possible concrete and informative examples of a Monad. Specifically, it does not rely on the reader knowing a topic like an option type (unlike the current Overview example) which personally confused me when I was trying to learn Monads on my own.
I recognize that my own example is still highly imperfect, and I am sorry if this post comes off as arrogant, but I would really like to help improve this page, and I do think that my example would aid in that.
edit: Sorry, I don't know what I was thinking when I wrote this. Chalk it up to being too excited about contributing.
--Kraic (talk) 21:21, 6 December 2019 (UTC)
Not useful for non-Haskell programmers
Almost any programming language nowadays has some form of monads and thus many people will come here first looking for explanation and find something completely incomprehensible to them. IMHO this page should completely eliminate Haskell from overview and explain terms in plain English and perhaps some JavaScript (or TypeScript since generic types are pretty useful in fully explaining it?) like pseudocode. — Preceding unsigned comment added by 207.96.108.12 (talk) 15:27, 21 June 2021 (UTC)
- Hi there, the page could definitely still use more work so changes are welcome. I did a lot of editing a couple years back here, but mostly worked through my list of ideas; I just watch the talk-page because it's evolving & conceptual discussions still come up (plus I have one table for this page on my to-do list).
- For the code snippets specifically, there is a pretty clear consensus to minimize Haskell on the page (outside of one or two examples, like IO, for flavor). The catch is there's no real guidance on Wikipedia for functional pseudocode, so when I was doing a lot of editing, I wound up settling on a pseudocode that still looks a lot like Haskell. The thinking there was that it is concise, abstract, de-emphasizes execution order, and often resembles functional math notation, especially if you leave things like lambda calculus implied. But there was also a bit of incrementalism in that decision. I left a long, rambling debriefing for my choices in the talk archives.
- If you do have something else in mind though, I'd go for it. I think pseudocode as close as possible to basic math notation (mapping arrows, "f(x)" style functions, etc.) fits this topic well, especially for the (granted, probably very rare) non-programmers that stumble onto the article. So I lean more towards something that looks like Haskell than imperative code in this case, even if it's a popular language, but that's just me. --Zar2gar1 (talk) 21:20, 23 June 2021 (UTC)
- I just rewrote the An Example: Maybe monad section and the introduction to use less haskell as well as being more clear. I used Rust for the code which is my preferred language and I think has similar syntax to other popular languages like Python & C++. I will try to do the rest if I have time. Any critiques? I'm a little new to Wikipedia editing. Zyansheep (talk) 05:44, 22 November 2021 (UTC)
- Circled back to Graham Hutton's 2016 book to expand/generalize the Rust examples. They all work together to get beyond any H. syntax. Used Failure/ Success as generic concepts from (Hutton 2016) to show the role of bind in the languages used (H., Rust, F#, etc.) --Ancheta Wis (talk | contribs) 05:09, 4 January 2022 (UTC)
We should dehaskelize it
There's a big problem with this article. It's all Haskell. That's not good. We have to be more abstract. Maybe write a bunch of paragraphs regarding how a monad looks like in Scala, Java, JavaScript, C++, Rust, C#, etc. Vlad Patryshev (talk) 19:27, 4 January 2017 (UTC)
- Haskell is a huge contributor to the use of monads in functional programming, so it's logical that many sections are based on documentation written in it. (Some may say that writing in Haskell is being "more abstract"). We have examples in Javascript and F#. If you know of references that document the usage of monads in those other languages, by all means bring them here and we'll figure out the best way to include them in the article. Diego (talk) 09:55, 5 January 2017 (UTC)
- A Haskell-oriented explanation would be OK if it also explained enough Haskell details used so readers needn't already know Haskell to follow along. Grokking monads is difficult so we can't really expect readers to simultaneously make lots of successful inferences about Haskell. This is doubly important since you can't get far in Haskell in turn without understanding monads.
- Please explain the syntax used, also its precedence (or use enough parentheses to avoid that). Are newlines significant? What determines which monadic type's
Just
,return
, or>>=
get called in presented example expressions such asJust 10 // Just 5
? Type classes, parameterized types, operator overloading, type inference,()
, ... What's the relationship betweenJust
,unit
, andreturn
? When the article says “a monadic value:M a
”, is that really a variable, a type, or both? - An alternate way to explain monads would be in a more familiar programming language. Using an object oriented language would answer the question of which
Just
andbind
get called, but it ought to be a language where types are first class values like JavaScript, Ruby, or Smalltalk. - That said, this page has improved dramatically over the last few years. 73.93.185.77 (talk) 01:55, 12 January 2017 (UTC)
- I'm afraid explaining the syntax of Haskell is outside the scope of this article. What it could do is better identify what features of the language are used in each example (enumerated types, pattern matching, etc).
- Adding examples in imperative languages wouldn't be a good idea, methinks; monads and object-orientation don't mix well, as the contrived Javascript example shows. IMHO one should have at least a basic grasp of functional programming before trying to understand monads; this is the scope where they are more useful anyway.
- In imperative languages you can use mutable state, so one of the main selling points of monads for strict functional languages is not needed there. And the other uses, for handling data structures and control threads, would require a syntax in an imperative language too awkward to be useful. Diego (talk) 13:29, 12 January 2017 (UTC)
- Maybe this could be a starting point to explain things: What would one do in an imperative language? Why is this not possible (or at least not that easy) in a functional language? In what way does the concept of monads solve this problem? 217.61.234.177 (talk) 07:37, 15 July 2020 (UTC)
- Problem solving can take many forms; please see reframing (in the sense of denotational semantics) for one approach to problem solving. --Ancheta Wis (talk | contribs) 13:48, 18 July 2020 (UTC)
- How does this relate to the suggested way of introducing monads? 217.61.234.177 (talk) 08:08, 19 July 2020 (UTC)
- Subjunctive mood and reframing are part of Haskell: as an example,
let tmp::b = g x in f tmp
can be read lettmp
beg
applied tox in f tmp
where the compose operator('∘') f g
has type (b→c)→(a→b)→a→c [1]: minute 11:45
- Subjunctive mood and reframing are part of Haskell: as an example,
- How does this relate to the suggested way of introducing monads? 217.61.234.177 (talk) 08:08, 19 July 2020 (UTC)
- Problem solving can take many forms; please see reframing (in the sense of denotational semantics) for one approach to problem solving. --Ancheta Wis (talk | contribs) 13:48, 18 July 2020 (UTC)
- Maybe this could be a starting point to explain things: What would one do in an imperative language? Why is this not possible (or at least not that easy) in a functional language? In what way does the concept of monads solve this problem? 217.61.234.177 (talk) 07:37, 15 July 2020 (UTC)
References
- be is "Subjunctive = " and part of the Haskell let syntax, as are
in f tmp
(ie, in f applied to tmp) andwhere
, which serve to Reframe the terms of some expression which are used to define a function such as compose, for example. (The section('∘') f g
means f ∘ g, read as f follows g, and the a,b,c are polymorphic type variables, in Haskell. −It may help to mentally separate the concepts reduce, bind, eval, and apply in your further readings. The articles sometimes gloss over differences in these separate concepts when discussing them in examples. A-normal form can be a useful reduction.) Evaluation strategy#Call_by_need says "Haskell only supports side effects (such as mutation) via the use of monads". - --Ancheta Wis (talk | contribs) 02:55, 9 August 2020 (UTC)
- See Gabriel Gonzalez' Haskell for all (26 Oct 2014) How to desugar Haskell code for a 5-line, internally consistent, mental model of Haskell, and how to reduce/rewrite its expressions into their equivalents (which depends on how you intend to apply those expressions). --Ancheta Wis (talk | contribs) 05:31, 4 January 2022 (UTC)
- be is "Subjunctive = " and part of the Haskell let syntax, as are
Uncertainty about the term's etymology
The clause "due to category-theorist Saunders Mac Lane" suggests that Mac Lane invented the term. This appears to be an exaggeration: Mac Lane may have popularized it (Categories for the Working Mathematician, 2nd Ed., p.138), but Where does the term “Monad” come from? documents ambiguity about the original source. This Week's Finds in Mathematical Physics (Week 200) credits Jean Benabou, whereas OPERADS, ALGEBRAS AND MODULES implies that J. P. May either invented the term or advocated it to Mac Lane before the latter published CftWM.
Mac Lane offers no definitive explanation of the name in CftWM, but his book is clearly the most reputable source among those I cited above. Absent an authoritative source, perhaps we should reword the "due to..." clause to highlight the ambiguity and more conservatively describe Mac Lane's role?
Monad (category theory) is similarly loose regarding attribution and should be clarified. Etymology? contains a brief but inconclusive discussion about the term's origin. — Preceding unsigned comment added by Maniaphobic (talk • contribs) 03:07, 27 June 2019 (UTC)
- In the same vein ".. researchers working with Haskell eventually generalized the monad pattern" might be rephrased as ".. in the 2010s researchers working with Haskell eventually recognized that monads are applicative functors". (This leads back to Mac Lane as well.) page 138 of Categories for the Working Mathematician --Ancheta Wis (talk | contribs) 06:05, 27 June 2019 (UTC)
List example
§ Another example: List claims • is bind, but then defines it as Kleisli composition, which is quite different. I also have no idea what ° is supposed to mean: is it the Kleisli star? But we don't really need to use it in this pseudocode (it's a trivial embedding of a subset of arrows in one category as arrows in another category - we're not discussing the category-theoretical underpinnings at this point) and "f° := unit•f = f•unit" is nonsense - "unit•f = f•unit" is a law for •, not a definition of °. Hairy Dude (talk) 16:54, 30 June 2019 (UTC)
- Perhaps the editor who contributed it might defend it; otherwise I agree it can go. (Note: the citation to Dan Piponi's discussion motivates the contribution, for me.) --Ancheta Wis (talk | contribs) 23:53, 30 June 2019 (UTC)
- How about now? Just swinging by, but I've done a variation on the diagram similar to one I tried a while back. The original contributor didn't like my changes, and since this is just an occasional hobby / writing practice, I had no interest in an edit war. I don't think they're on Wikipedia anymore though, and they never responded to my points here on the talk-page.As for the old caption, I think that was a misinterpretation of Dan Piponi's post. Since the ° is appended to the individual "sqrt" & "cbrt" functions, I think it was supposed to correspond to the ' in the blogpost. But that's just to distinguish the multivalued, complex functions from the simpler real ones; it can't be the monadic lift for List because you have to consider the individual function semantics to apply it.And the • as bind was only correct in the 1st & 4th identity. Besides not matching up with the article text, I'm pretty sure the old caption was mixing up bind with Haskell function composition (f . g) when reading the 2nd & 3rd identity from the blogpost. --Zar2gar1 (talk) 06:13, 10 February 2021 (UTC)
- The image has lost the parallelogram/rectangle syntax: parallelograms denote input/output (complex numbers or lists); rectangles denoted functions; input can only be fed into one function (can't feed one input into [cbrt] and [>>=cbrt]); [cbrt] should not accepts a list because it is not lifted.
- The diagram should look something like this (rotated here for easier typing):
[cbrt°] ↘ ↗ < 8> → [cbrt°] → < 2, 2e..., 2e...> ↘ <64> → [sqrt°] → <8, -8> → [map] [concat] → < 2, 2e..., 2e..., -2, -2e..., -2e...> ↘ <-8> → [cbrt°] → <-2, -2e..., -2e...> ↗
- ...which represents this far less comprehensible equasion:
sxrt(64) = (cbrt°•sqrt°)(64) = concat(map(cbrt°,sqrt°(64))) = concat(map(cbrt°,concat(map(sqrt,unit(64))))) = concat(map(cbrt°,[8,-8])) = concat(cbrt°(8),cbrt°(-8)) = concat(concat(map(cbrt,unit(8)),map(cbrt,unit(-8))) = concat([2,2e...,2e...],[-2,-2e...,-2e...]) = [2,2e...,2e...,-2,-2e...,-2e...]
- Using concat (append), map, lift (°), unit, and bind (•) as defined in the cited source. I hope I got that right. CrossCriss (talk) 17:11, 19 April 2021 (UTC)
Hi there, so I think you make some good points about the flowchart, such as the boxes. My intent was actually for them to make a slightly more general distinction: rectangles for (first- or higher-order) functions that allow evaluating the expression further, parallelograms for the expression itself, including self-contained rewrites. That's not immediately clear though, and perhaps a couple more style variations would be good (for example, to point out that map is a higher-order function).
You're also right that cbrt (without >>=) only accepts a simple input, not the list. Putting cbrt with the list in that 1st parallelogram on the left, without further reduction, was meant to show the expression can't be evaluated until map is applied. That's not particularly clear though, so if you can think of a clearer way to put it, that would be great.
That said, like I wrote above, I think the ° (' in the original blog-post) should only be considered as a shorthand to distinguish monadic functions (like the use of x' variables in physics), not an official, valid lift. A few of his examples are derived by lifting, but if you notice in the multivalued trig example, he never formally defines how to go from the real-valued cube root to the multi-valued complex one. To do so requires facts about the underlying function (how to do complex roots), but the lift should be a property of the monad, which is only a generic list.
Or another way to look at it: in his first example with the writer monad (what he calls "debuggable functions"), when he does explicitly describe lifting a function f, he doesn't specify anything particular for a debug message. He only tags the function with the empty string because anything more implies knowledge of the function's specifics, but the lift has to be generic to the monad, which only specifies that comments will be appended. To specify what comment a monadic function should output, that needs to be defined along with the monadic function itself.
I'm still not sure it's correct to consider the • a bind either. One immediate issue is that it doesn't match a valid infix bind's type signature: one input should be a monadic value, not a 2nd monadic function (funny enough, IIUC in category theory terms, bind is itself a "lift" from (a -> Mb) functions to (Ma -> Mb) ones). Now if it's meant to be like the * from the blog-post, that's actually monadic composition (our articles uses >=> like in Haskell for now); that does have the correct type-signature, but it's not directly equivalent to bind or the composition of join & map. --Zar2gar1 (talk) 07:02, 20 April 2021 (UTC)
"Non-technical explanation" and the monad tutorial fallacy
The "Non-technical explanation" section was awful. I've removed the whole thing as it's actually more confusing than the technical introductory section. Monads are easy to describe once you know how they work using any number of analogies, but is there any reasonable way of describing monads to someone who hasn't already learnt the concept the hard way?
This blog post on the "monad tutorial fallacy" is I think insightful; there's really no substitute for doing the hard work of understanding, and once you've done it, your insight is still hard (impossible?) to communicate with others, because the hard work simply cannot be avoided. -- The Anome (talk) 13:25, 8 June 2020 (UTC)
- Except that's only true in a limited way. Mathematics pedagogy has known for a long time that often the best way to get someone to understand something is to begin by describing concrete instances and only once the intuition has been developed for the concrete do we generalize and abstract. Think about how you learned about the real numbers. Did you start by sayings its the unique Dedekind complete ordered field or hand you a definition in terms of equivalence classes of Cauchy sequences? Of course not! You started by learning to manipulate concrete examples of reals, first the rationals and then you started to add some special definable real numbers like pi which you can approximate and then we say ok now it's like that but we generalize even to values which you can't define and give a fully formal definition.
- I think the linked article does have a good point but I'd phrase it as this. When introducing a new abstraction it's important to be clear on whether you are giving a concrete example of a type of thing that falls under the concept or something that can kinda motivate the concept or if you are suggesting that a description captures the complete nature of the concept. Peter M. Gerdes (talk) 16:25, 2 October 2021 (UTC)
"f returns a defined value of type Maybe U"
One of the comments in >>= operator for Maybe says:
"f returns a defined value of type Maybe U".
Is that "defined" correct?
(It sounds like it's saying that that function call can't return Nothing. However, function f's return type is Maybe U, so can't the function return _either_ "a defined value of type Maybe U" _or_ the Nothing value of type Maybe U?)
100.36.43.9 (talk) 18:36, 6 March 2021 (UTC)
- I think the main gist of the comment is correct, since it's placed with the 1st branch of the if statement. You're right though that it does sort of imply that Nothing wouldn't be a valid Maybe value, which isn't correct. I'll tweak the wording to emphasize it wraps a defined Just value within the Maybe type. --Zar2gar1 (talk) 23:11, 20 April 2021 (UTC)
Consistency in notation
The first section of the article seems to be using `:` for type declarations, e.g.
unit : T → M T
while the Analysis section is using it to indicate the definition of the function, e.g.
map φ : (a → b) → (ma → mb)
This is confusing - it would be good to rewrite the Analysis section to be more consistent with the intro. We could potentially write both the type and the definition:
map : (T → U) → M T → M U
map φ ma = ?
Also, in the Analysis section, I think we should explicitly state the types of ma
, mmma
, etc, to avoid confusion (I found it hard to work out). --Jordan Mitchell Barrett (talk) 21:11, 16 September 2021 (UTC)
- The part that has been left unsaid in the article is that 'whitespace is an operator' .[1] Thus in the pseudocode in the article, whitespace can mean function application, or even more, depending on the language. The pseudocode is written in mathematical style, or in functional programming style (which dates back to Miranda (programming language)). --Ancheta Wis (talk | contribs) 11:30, 28 October 2022 (UTC)
- Hi there, first off, the : symbol is actually one bit I really didn't think through much. IIRC Haskell uses it for type signatures, and it's not that different from its use in plain English or function signatures in math. So I just ran with it without thinking too much about it; if some inconsistency jumps out at you, I don't see a reason not to change it.
- As for the the use of
ma
in the Analysis section, I'm not sure I follow about making the types explicit. Do you mean include the signatures in an expanded form? I tried to stay concise, but if you think adding some details clarifies things, that's always an improvement. - It is a little tricky because the laws are pretty generic, as long as
m
is monadic and the same variable means the same thing on both sides of an expression. Repeating the variable for the monad type was the simplest way I could think of to express the nesting you see in the laws (and like in the List example, when you're in that transition state after mapping the monadic function but before reducing again with join). Zar2gar1 (talk) 21:24, 25 October 2021 (UTC)
References
- ^ Daniel Wagner (15 Jul 2019 at 1:10) Is whitespace either used as a function application operator or a word separator in answer to bradm
IFF or equality?
Maybe I'm just being dumb bc I'm just a mathematician who doesn't do category theory and may be unfamiliar with some of the programming/category theory specific notation but shouldn't the statement of the Monad laws use an equals symbol not a double arrow (as it appears in iPhone Wikipedia app)? If it is correct as written it might help to add a note explaining that it's not meant to be read as the usual logical connective. Peter M. Gerdes (talk) 16:06, 2 October 2021 (UTC)
- No, you're definitely not being dumb or missing some deep secret; while the choice was intentional, it was mainly a compromise for the pseudocode. I thought it could act as a (metalanguage?) hint that the monad laws aren't necessarily programmed, but ultimately logical propositions about a potential monad. They may or may not be true, based on whether the object is actually verified to be a monad.
- If anyone wants to change it, I'm definitely not opposed. I'd just stay away from the single = sign since that's used for assignment in so many programming contexts, but a == or === is pretty common for equality in several languages. Ideally though, we'd still want to emphasize the laws (typically) aren't checked within the program, but outside of it logically. Zar2gar1 (talk) 21:24, 25 October 2021 (UTC)