3 ms·
But for such a monad to be valuable, wouldn't you also need 3a. A method for extracting the value from the box String myValue = Async.val(myAsync); Or, a
by tremon 4y ago
But for such a monad to be valuable, wouldn't you also need
3a. A method for extracting the value from the box
String myValue = Async.val(myAsync);
Or, alternatively, to be able to re-use the entire standard library for your boxed values (which is not possible in Java, FAFAIK):
3b. Take a plain-valued function and lift it to accept boxed values:
Func<Async<String>> asyncJoin = Func.lift<Async>(String.join);
- chopin 4y agoJava solves this with map as instance function (transfering the function inside the box). And there are several extraction functions (See Optional for an example).
- deleted 4y ago[deleted]
- btschaegg 4y agoMy take would be: Your 3a is certainly necessary in order for each individual monad to be useful, but it is not general (i.e it depends on the monad how you do it). Therefore, it's not part of the criteria of what it means to be a monad. Examples: - Async: Block and wait for your Async<T> to finish or fail. (Note that Async<T> can still be useful without that if you can simply register a final continuation callback with side effects) - Option: Check if there is a value and unwrap it if that's the case. Or, maybe more idiomatic: Some way to write a `match` statement ("if there's a value, do A. Otherwise do B. Both have to return the same result type") - List: Provide ways to check the length and access each individual value in the list. - Stream: Provide a way to wait for the next value. …and so on and so forth. Your 3b is implementable in terms of `bind` and `return` (and, in case your monad is also a functor, even in terms of `map`). Edit: To drive the point about 3a home a bit more: The reason why monads (and functors) as a pattern are interesting is that they provide the formalistic means to write "imperative" code by writing pure functional "in between" code: Do A …and then do B …and then do C Different monads essentially only influence what "and then" means. A lot of languages have syntactic sugar for this kind of "and then" lists, for example: Haskell: do notation F#: Computation expressions (e.g. `async` or `seq` blocks) Python, C#, Javascript: Async methods and functions C#: Inline SQL with LINQ Rust: `try` and `async` blocks You'll note that each of these notations return the final monad instance without unwrapping it. That's because "unwrapping" is either not general enough for the notation or not always desirable. I.e. an `async` method in C# returns a `Task<T>`, you'll have to block for the result yourself. So, the "Monad" pattern is only concerned with how you can compose operations, not with how you can get to the resulting value.
- substation13 4y agoExcept many of those syntactic-sugars do not operate on well-formed monads. JavaScript collapses a Promise<Promise<t>> to a Promise<t>, for example.
- codebje 4y agoIn general you can't take the value from the box: you can't make an async computation non-async; you can't make a non-deterministic function deterministic; you can't make a possibly-failed result successful. The await keyword might make it look like you can escape the box - but in effect a statement like "let x = await y" is just expanding the async box around y to also be around the bock containing that statement. Since we already have a function to take a plain value to one in a box ((1) above) and a way to apply a function that turns a value from a box into another boxed value, lifting is just function composition: box.lift(f) = box.map(val -> from(f(val)))