Some languages support a special "do notation" that allows to express monadic operations more naturally.
However, there is an even more powerful option, that I'd call "in notation" (I came up with it, but it's obvious, so I'm sure there's some language that has something like it). The idea is that we add an "in" keyword, and in-types, which are the type "in T" where T is a monadic type. In-types are physically represented as the monadic type, but semantically behave like the type contained in the monad; they are constructed with the expression "in x". The "out" keyword does the opposite, converting an in-type to the wrapped type. Operations performed on in types actually act on the value inside of the monad, as better specified below Quick examples: out(in Some(3) + 6) gives Some(9) out(in Some(3) + in Some(6)) also gives Some(9) out(in Some(3) + in None) gives None out(in ~[1, 2, 3] + 10) gives ~[11, 12, 13] out(in ~[1, 2, 3] + in ~[10, 20, 30]) gives ~[11, 21, 31, 12, 22, 32, 13, 23, 33] Internally, when the compiler encounters any expression including an in-type (expressions include control flow constructs), it proceeds like this (considering its operands from left to right): 1. Optionally, if the expression is correctly typed (e.g. calling a function that takes an in-type), it compiles it normally 2. If the expression does not have an in-type value itself, it converts the expression into a closure, and passes it to map() 2. If the expression does have an in-type value itself (for example in x + in y has an in-type when viewed as a function of in x, due to the presence of in y), it converts out(expression) into a closure, and passes it to flat_map() Non-movable control flow like return or break is forbidden in expression involving in-types (they can be implemented with a flag, but that causes other equivalence issues). The advantage of this is that special do-notation syntax is not required, and one can naturally manipulate the values. The disadvantage is that it adds a layer of "magic", making what the code actually does less obvious. This is particularly true with list-like monads, where simple things like (in x) + (in y) actually become a double loop with quadratic run-time; this can be optionally avoided by only allowing "in notation" to be used with monads that call the closure once. Also, side effects will be performed a different amount of times depending on the monad values, which may also not be obvious. Note that there are a lot of details that I omitted for the sake of brevity, and would need to be handled. _______________________________________________ Rust-dev mailing list [email protected] https://mail.mozilla.org/listinfo/rust-dev
