Category talk:Monads: Difference between revisions
No edit summary |
|||
(5 intermediate revisions by one other user not shown) | |||
Line 38:
::::::::::::(1) While the general case algebraic data type is not monadic, I've yet to see an algebraic data type which cannot be used in a monad.
::::::::::::(2) Change of list length is roughly equivalent to a type change. --[[User:Rdm|Rdm]] ([[User talk:Rdm|talk]]) 21:29, 31 January 2016 (UTC)
:::::::::::::I think these issues may now be resolved by the edits, but FWIW, the problem with characterising monads by foregrounding algebraic datatypes was mainly one of emphasis. A monad is a category – a set of related morphisms or functions, if you like – it's not a datatype – and the simplest monad, in which the Return function is equivalent to the ID function [[wp:Monad_(functional_programming)#Identity_monad|(see under Identity Monad)]], involves no 'wrapper' or modal context at all. From the practical coding perspective, a monad is a pattern of function nesting, and the practical steps involved in creating that pattern consist of writing two functions. As you point out, a useful monad is very likely to involve some kind of modal wrapper (though even the identity monad is used in programming), but while that may be an empirically (though not formally) *almost* necessary condition, it is neither practically sufficient, nor conceptually central enough to provide an adequate substitute for foregrounding the monadic functions themselves, and the value of the function nesting which they enable. (In my personal view :-) [[User:Hout|Hout]] ([[User talk:Hout|talk]]) 17:42, 2 February 2016 (UTC)
::::::::::::::Ok, so why do you distinguish between list monad and maybe monad? More specifically, if I am working in a language where there's no enforced distinction between a list and a maybe (where the distinction comes from the supporting code - how the data gets used), it seems that I'd use identical implementations of <code>return</code> and <bind>. Do you disagree with this? If so, why do you say there's a problem with characterising monads by foregrounding algebraic datatypes? (If not, just let me know and I'll be happy.) --[[User:Rdm|Rdm]] ([[User talk:Rdm|talk]]) 08:07, 3 February 2016 (UTC)
==Structure of Monads on Rosetta Code==
Line 44 ⟶ 46:
: Yes, I agree – I think that would work better [[User:Hout|Hout]] ([[User talk:Hout|talk]]) 09:37, 31 January 2016 (UTC)
:: Looks like that turned out nicely. It feels much more organized and uncluttered. [[User:Domgetter|Domgetter]] ([[User talk:Domgetter|talk]]) 08:52, 1 February 2016 (UTC)
::: Good. A useful category to introduce, I think. Perhaps a 3rd entry ? The Writer monad is useful, and quite easily understood and written - maybe worth adding, for further comparison across languages [[User:Hout|Hout]] ([[User talk:Hout|talk]]) 19:58, 1 February 2016 (UTC)
|
Latest revision as of 08:07, 3 February 2016
Lead Section
A suggestion - perhaps the list monad ? It's a useful route to cartesian products, and enables filtering and list comprehension expressions.
See, for example: https://en.wikibooks.org/wiki/Haskell/Understanding_monads/List
For the Maybe monad, the task description probably needs to add:
1. A brief motivation - for example safe versions of partial numeric functions 2. A couple of specific 'safe' functions to implement and compose
Perhaps, for example, avoiding division by zero, or square roots (or logs?) of negative numbers ?
- I made the lead section more explicit to allow editors to implement a List or a Maybe Monad, and in the Clojure example I went ahead and implemented both to show that anyone can do both. As for a section on motivation, I'm all for it, and I'm new to Rosetta Code so I'm wondering if that's a common practice. Also, I figure if someone is coming to the page, they're past the point where they need a motivation to learn about monads ;). But like I said, I like the idea, so if you want to add a blurb in the lead about the benefits of monads and their common use cases, feel free to update! Domgetter (talk) 12:01, 30 January 2016 (UTC)
- I think you have assumed too much about the relevance and implementations of monads. I've left some quips in the J implementation to illustrate this issue. But I'll update the description with a bit about motivation. --Rdm (talk) 18:51, 30 January 2016 (UTC)
- Contributors may not need much motivation, but helpful, I think, to frame things more for readers. In that context good to see some introductory and motivational text developing. On the specifics, I might personally tend to use the term 'pattern' in preference to 'mechanism'. The pattern itself has an algebraic or category theoretic definition, but the key point for a programmer is really that it provides a well modelled and reliable approach to allowing composition of functions whose arguments consist of modalised or wrapped data types. The nature of the wrapping and its value/relevance varies (protection against illegal values for partial functions, binding of names to multiple possible values etc etc), but the possibility of composition is the core value and relevance of all monadic patterns.Hout (talk) 22:12, 30 January 2016 (UTC)
- Hmm... "pattern", like "mechanism" is a somewhat ambiguous term with multiple plausibly relevant definitions for something like this (and also wit a good variety of not-so-relevant definitions). I don't really have any strong preference for one term over the other, but if the distinction matters it would probably be good to provide some exposition and/or links to suggest something about the relevant aspects of that distinction - our audience here is going to include programmers working with languages or in environments where these sorts of distinctions are meaningless or, worse: misleading. --Rdm (talk) 23:15, 30 January 2016 (UTC)
- PS not sure, FWIW, that I am convinced by the necessity (or empirical reality) of a connection between monadic patterns and multiple dispatch :-) The point about the bind function is that it applies a type-specific function to whatever is inside the monadic wrapping. There is no need for run-time branching on a detected type, or for functions which can operate on multiple types Hout (talk) 23:03, 30 January 2016 (UTC)
- Correct - the whole point of the monad definition is to hide that implementation detail. But there is no need to hide something which does not exist. --Rdm (talk) 23:17, 30 January 2016 (UTC)
- Rereading your explanation in terms of unfied handling of multiple types I do wonder whether a misundertanding might have arisen ? No polymorphism is entailed, and none of the functions involved, either on the surface, or in the implementation of a particular type of monad, either necessarily can or pretend to apply to more than one type. Or do you simply mean that composition of wrapped data can be achieved using the same technique with various types of wrapping ? Hout (talk) 01:08, 31 January 2016 (UTC)
- Yes, I mean that that these monads are about working with wrapped types (and the point is to be able to work with more than one of these wrapped types). That said, the word "pattern" also can carry a connotation of "pattern matching" which in turn can carry an implication of polymorphism - not a part of this task, certainly, but for some readers the use of the term "pattern" might imply something different. --Rdm (talk) 01:36, 31 January 2016 (UTC)
- OK, I think I might disagree with you that "the point is to be able to work with more than one of these wrapped types". The fact that Kliesli composition is useful with various wrapping types does enable a unified treatment of various monads in some coding interfaces, but the point or value of the Maybe monad is not, I think, that there are other monads - it is that we can get the type-safety of a wrapper without losing the structuring value of functional composition. Similarly, the value and point of the list monad is not that there are other monads - it is that we get a simple mechanism (by combining composition with the binding of a name to multiple values) for obtaining cartesian products, expressing set comprehensions, filtering etc. In other words, your formulation appears to be locating the essential value of monadic patterns in as aspect that seems a little more peripheral or incidental to me. Hout (talk) 02:28, 31 January 2016 (UTC)
- I do not know if your point here is that the "bottom type" is not a distinct type from number or if your point here is that you do not "work with" the bottom type. If you could clarify that point maybe I could understand what you are getting at? --Rdm (talk) 05:03, 31 January 2016 (UTC),
- My point is that I think your formulation might mislead – the monadic pattern is not a technique for constructing types (it's a way of setting up a category with a particular set of morphisms, encoded by specific functions), and it neither entails nor conceals multiple despatch. To answer your question, which concerns (and is perhaps over-determined by a focus on ?) one particular monad ( the Maybe monad ), none of the top level or called functions which constitute the morphisms of the category are polymorphically applicable to two different types (e.g. to a choice between bottom and a non-bottom value), and none branch on whether they are presented with bottom or not bottom.
- I think it might be more helpful to readers to simply 1. introduce monads as a way of working with wrapped/modalised data which preserves the possibility of composition 2. Emphasize that although each monad involves (in fact is defined by) a 'bind' function (for piercing the wrapping and applying a function directly to its contents) and a 'return' (or wrapping) function, the behaviour and value of particular monads is very variable and quite unpredictable. The value and nature of the list monad really has nothing more in common with the Maybe monad than those two defining functions. To characterise it as a way of constructing lists, or as involving some kind of multiple despatch, might tend, I think, to lead astray or simply confuse Hout (talk) 08:43, 31 January 2016 (UTC)
- In many typical implementations, a monad is implemented as a type. So I do not know what you mean by "the monadic pattern is not a technique for constructing types". Maybe, though, you have a specific idea about what techniques are, and that is important? Then again, people use the monadic pattern is to deal with other types (plural) and of course with the values which those types can take on. so I don't know what you mean by "it neither entails nor conceals multiple despatch". I understand that there will be examples which do not require multiple dispatch, but I would ask you to find a more generally relevant (cross-language) phrase if you want to fix that issue.
- As for your "none of the top level or called functions which constitute the morphisms of the category are polymorphically applicable to two different types" statement, that is exactly what I meant when I said it hides multiple dispatch. That said, I am not wedded to the term "multiple dispatch" -it's really no concern of mine whether the handling of types is at "compile time" at "run time" at "parse time" or at "lunch time". And if you can come up with a description of multiple type handling which uses less jargon, I'd be all in favor of that.
- That said, we are talking about language features, here, and we are also in a context where we have to discuss what's relevant in contexts involving many languages. I think your points would be relevant if we could assume a language which has a native implementation of monads. Your points could also be relevant in a few other languages. However, that is not sufficient to convey the ideas to users of other languages.
- If you try to narrow the discussion to be specifically tailored to readers who already know what you are talking about, you are not going to convey any useful information to the reader.
- If you are going to address the rosettacode audience, you are going to need to break out of your jargon focus enough to convey to programmers and users of languages which do not have a native monad implementation enough about how it *works* (as opposed to how it's *implemented*) for them to implement something.
- (As an aside, I think the relationship between "list" and "maybe" might be closer than you think. Yes, the implementations will usually be distinct. But if you constrain a list to have a maximum of one element, the zero length list corresponds to the bottom type and the 1 length list to the other type. That's only "nothing to do with" if you do not appreciate what analogies have to do with reasoning - and that hypothetical lack of appreciation, if someone were inflicted with it, could be a significant handicap in many situations.)
- Anyways, I think I understand where you are coming from. And, if you can come up with a better phrasing which clearly communicates what needs to be implemented to users of arbitrary languages - something which focuses on what happens in the implementation rather than on jargon or on what monads are not - that would be great. However, when I look out at what's been done for various popular languages, I find that a number of them seem to have a only specific monad implementation which looks an awful lot like the maybe implementation - in other words, not at all the sort of generality which I think you are trying reach for. So ... perhaps what we are talking about here probably has more to do with proper use of english grammar than it has to do with how to make a working monad implementation? --Rdm (talk) 09:43, 31 January 2016 (UTC)
- Perhaps the solution is to break this task out into several specific monads, and present the nature and value of each individually, avoiding entanglement with too much algebraic abstraction. This might enable something like, in one case: "The Maybe monad is a way of safely composing partial functions, which avoids the need for exception handling" and in another "The List monad is a way of composing functions whose argument is bound to a range of possible values, rather than to one unique value. It enables simple encoding of cartesian products and set comprehension expressions." ("A way of ..." can then be concretised in terms of implementing two functions - bind/inject/chain (whatever you want to call it) and return/wrap).
- PS I think perhaps your formulation offers a description of algebraic data types rather than of monads. Hout (talk) 09:31, 31 January 2016 (UTC)
- Where are you implementing monads without any such types? Would you object to a discussion of types which happens to also mention values that can be represented using those types? --Rdm (talk) 09:43, 31 January 2016 (UTC)
- Useful monads are likely to involve algebraic datatypes, just as elephants are likely to involve lungs, but monads are not defined by their algebraic datatypes any more than elephants are defined by their lungs. Not all algebraic datatypes are monadic, and not everything that has a lung is an elephant. The list monad just involves ordinary lists, and no polymorphism. What makes it monadic (and useful) is the bind and return functions. Categories are defined by their morphisms - not by the nature or contents of their objects in general, or by the presence of algebraic datatypes in particular. I suggest we adopt the solution below, and make sure that we clarify what functions have to be implemented to ensure that composition works, and that composed functions are not presented with arguments of the wrong type. Hout (talk) 16:51, 31 January 2016 (UTC)
- (1) While the general case algebraic data type is not monadic, I've yet to see an algebraic data type which cannot be used in a monad.
- (2) Change of list length is roughly equivalent to a type change. --Rdm (talk) 21:29, 31 January 2016 (UTC)
- I think these issues may now be resolved by the edits, but FWIW, the problem with characterising monads by foregrounding algebraic datatypes was mainly one of emphasis. A monad is a category – a set of related morphisms or functions, if you like – it's not a datatype – and the simplest monad, in which the Return function is equivalent to the ID function (see under Identity Monad), involves no 'wrapper' or modal context at all. From the practical coding perspective, a monad is a pattern of function nesting, and the practical steps involved in creating that pattern consist of writing two functions. As you point out, a useful monad is very likely to involve some kind of modal wrapper (though even the identity monad is used in programming), but while that may be an empirically (though not formally) *almost* necessary condition, it is neither practically sufficient, nor conceptually central enough to provide an adequate substitute for foregrounding the monadic functions themselves, and the value of the function nesting which they enable. (In my personal view :-) Hout (talk) 17:42, 2 February 2016 (UTC)
- Ok, so why do you distinguish between list monad and maybe monad? More specifically, if I am working in a language where there's no enforced distinction between a list and a maybe (where the distinction comes from the supporting code - how the data gets used), it seems that I'd use identical implementations of
return
and <bind>. Do you disagree with this? If so, why do you say there's a problem with characterising monads by foregrounding algebraic datatypes? (If not, just let me know and I'll be happy.) --Rdm (talk) 08:07, 3 February 2016 (UTC)
- Ok, so why do you distinguish between list monad and maybe monad? More specifically, if I am working in a language where there's no enforced distinction between a list and a maybe (where the distinction comes from the supporting code - how the data gets used), it seems that I'd use identical implementations of
- I think these issues may now be resolved by the edits, but FWIW, the problem with characterising monads by foregrounding algebraic datatypes was mainly one of emphasis. A monad is a category – a set of related morphisms or functions, if you like – it's not a datatype – and the simplest monad, in which the Return function is equivalent to the ID function (see under Identity Monad), involves no 'wrapper' or modal context at all. From the practical coding perspective, a monad is a pattern of function nesting, and the practical steps involved in creating that pattern consist of writing two functions. As you point out, a useful monad is very likely to involve some kind of modal wrapper (though even the identity monad is used in programming), but while that may be an empirically (though not formally) *almost* necessary condition, it is neither practically sufficient, nor conceptually central enough to provide an adequate substitute for foregrounding the monadic functions themselves, and the value of the function nesting which they enable. (In my personal view :-) Hout (talk) 17:42, 2 February 2016 (UTC)
- Useful monads are likely to involve algebraic datatypes, just as elephants are likely to involve lungs, but monads are not defined by their algebraic datatypes any more than elephants are defined by their lungs. Not all algebraic datatypes are monadic, and not everything that has a lung is an elephant. The list monad just involves ordinary lists, and no polymorphism. What makes it monadic (and useful) is the bind and return functions. Categories are defined by their morphisms - not by the nature or contents of their objects in general, or by the presence of algebraic datatypes in particular. I suggest we adopt the solution below, and make sure that we clarify what functions have to be implemented to ensure that composition works, and that composed functions are not presented with arguments of the wrong type. Hout (talk) 16:51, 31 January 2016 (UTC)
- Where are you implementing monads without any such types? Would you object to a discussion of types which happens to also mention values that can be represented using those types? --Rdm (talk) 09:43, 31 January 2016 (UTC)
- I do not know if your point here is that the "bottom type" is not a distinct type from number or if your point here is that you do not "work with" the bottom type. If you could clarify that point maybe I could understand what you are getting at? --Rdm (talk) 05:03, 31 January 2016 (UTC),
- OK, I think I might disagree with you that "the point is to be able to work with more than one of these wrapped types". The fact that Kliesli composition is useful with various wrapping types does enable a unified treatment of various monads in some coding interfaces, but the point or value of the Maybe monad is not, I think, that there are other monads - it is that we can get the type-safety of a wrapper without losing the structuring value of functional composition. Similarly, the value and point of the list monad is not that there are other monads - it is that we get a simple mechanism (by combining composition with the binding of a name to multiple values) for obtaining cartesian products, expressing set comprehensions, filtering etc. In other words, your formulation appears to be locating the essential value of monadic patterns in as aspect that seems a little more peripheral or incidental to me. Hout (talk) 02:28, 31 January 2016 (UTC)
- Yes, I mean that that these monads are about working with wrapped types (and the point is to be able to work with more than one of these wrapped types). That said, the word "pattern" also can carry a connotation of "pattern matching" which in turn can carry an implication of polymorphism - not a part of this task, certainly, but for some readers the use of the term "pattern" might imply something different. --Rdm (talk) 01:36, 31 January 2016 (UTC)
- Rereading your explanation in terms of unfied handling of multiple types I do wonder whether a misundertanding might have arisen ? No polymorphism is entailed, and none of the functions involved, either on the surface, or in the implementation of a particular type of monad, either necessarily can or pretend to apply to more than one type. Or do you simply mean that composition of wrapped data can be achieved using the same technique with various types of wrapping ? Hout (talk) 01:08, 31 January 2016 (UTC)
- Correct - the whole point of the monad definition is to hide that implementation detail. But there is no need to hide something which does not exist. --Rdm (talk) 23:17, 30 January 2016 (UTC)
- Contributors may not need much motivation, but helpful, I think, to frame things more for readers. In that context good to see some introductory and motivational text developing. On the specifics, I might personally tend to use the term 'pattern' in preference to 'mechanism'. The pattern itself has an algebraic or category theoretic definition, but the key point for a programmer is really that it provides a well modelled and reliable approach to allowing composition of functions whose arguments consist of modalised or wrapped data types. The nature of the wrapping and its value/relevance varies (protection against illegal values for partial functions, binding of names to multiple possible values etc etc), but the possibility of composition is the core value and relevance of all monadic patterns.Hout (talk) 22:12, 30 January 2016 (UTC)
- I think you have assumed too much about the relevance and implementations of monads. I've left some quips in the J implementation to illustrate this issue. But I'll update the description with a bit about motivation. --Rdm (talk) 18:51, 30 January 2016 (UTC)
- I made the lead section more explicit to allow editors to implement a List or a Maybe Monad, and in the Clojure example I went ahead and implemented both to show that anyone can do both. As for a section on motivation, I'm all for it, and I'm new to Rosetta Code so I'm wondering if that's a common practice. Also, I figure if someone is coming to the page, they're past the point where they need a motivation to learn about monads ;). But like I said, I like the idea, so if you want to add a blurb in the lead about the benefits of monads and their common use cases, feel free to update! Domgetter (talk) 12:01, 30 January 2016 (UTC)
Structure of Monads on Rosetta Code
Perhaps we should use the overall structure used for Sorting Algorithms. That is, make Monads redirect to Category:Monads, which lists all Monads, and then, e.g. the List Monad, make List_monad redirect to Monads/List_monad in the same way that Merge_sort redirects to Sorting_algorithms/Merge_sort. This way it fits an existing structure on the site, and it makes it clear that there are many different kinds of Monads. Plus, each kind of Monad can have a task tailored to its semantics. Any thoughts? Domgetter (talk) 09:25, 31 January 2016 (UTC)