feat: add maybe and result thread macros#1403
feat: add maybe and result thread macros#1403scolsen wants to merge 1 commit intocarp-lang:masterfrom
Conversation
These macros each thread the value of a Maybe or Result through subsequent forms only when the Maybe or Result is a Just/Success value, returning Nothing/Error otherwise. It's a convenient way to execute some sequence of forms when a Maybe/Result returning function is successful, immediately returning the error value otherwise.
|
I'm not sure about the |
hellerve
left a comment
There was a problem hiding this comment.
Can we add a test or two for these? Also, any particular reasons you didn’t go for quasi-quoting here?
No good reason, I just haven't rewritten my muscle memory yet 😅. Tests are a good idea, I'll add them + convert to quasi since it's more concise! |
|
I originally thought these were for chaining fallible operations (each step would return Result/Maybe), wondering if that would be more powerful. |
It would be, and I would personally love something equivalent to all of Kotlin's I guess in theory these operators can be expressed in terms of that more general operator? |
| ("threads the value contained in a Result through the following" false) | ||
| "forms iff, the Result is a Success" | ||
| "" | ||
| "Returns the erorr if the Result is Result.Error.") |
|
So if the composed functions produce a Nothing/Error in the middle of the chain, it is not aborted? (I didn't read the code very properly the first time, it seems) |
These macros just perform wrapping and unwrapping once and expect forms that operate on the interior value, so if you pass in a function that returns a result, your final value will have type I think @TimDeve was asking for a monadic bind, where the forms/functions you pass in also return the Result type so that you can chain them. I do have this in my typeclass lib but it might be nice in core too |
|
OK; thanks for the clarification. I have a feeling people will expect these to be monadic. |
|
The macro is kinda like doing apply + thread (without the lambda): (Maybe.apply (Maybe.Just x)
&(fn [y] (=> y
(+ 3)
(* 2)))) |
|
I see. I think the threading macros should do the same thing on each "step". |
|
yeah, let's just make it a monad I think. here's the way it's implemented in (doc >>=
("Expands into a form that sequences functions in a monadic context " false)
"using `bind`."
"```"
"(>>= (Maybe.Just 1)"
" &(fn [x] (pure (+ 2 x)))"
" &(fn [x] (pure (+ 3 x))))"
"=> (Just 6)"
"```")
(defmacro >>= [monad :rest functions]
(Monad.bind-forms-internal 'bind (cdr functions)
(list 'bind monad (car functions))))We could basically make these macros the same, just dropping the requirement to pass a complete The typeclasses lib also implements some haskell-esque do sugar: (doc m-do
("\"do notation\" for monads--just like Haskell's do notation, this " false)
"is sugar for binding the result of monadic actions to variables."
""
"```"
"(m-do [x (<- (Maybe.Just 1))"
" y (<- (Maybe.Just 1))]"
" (pure (+ x y)))"
"=> (Maybe.Just 2)"
"```")
(defmacro m-do [bindings actions]
(if (or (not (array? bindings))
(not (= 0 (- (length bindings) (* 2 (/ (length bindings) 2))))))
(macro-error
(String.concat ["m-do bindings must be contained in an array, "
"which must contain an even number of "
"<variable> <binding> forms, "
"like `let` bindings: "
"[x (<- (Maybe.Just 2)) y (<- (Maybe.Just 1))]"]))
(Monad.m-do-transform-bindings (reverse bindings) actions))) |
|
Seems like this got stuck in review limbo. Anyone has an opinion on whether to merge or close? (I'm leaning towards closing it). |
|
I think the general idea is really cool! I think I’d try to update some of my libraries to use it so I can provide some actual feedback? |
|
Absolutely! Happy to leave it around 😃 |
|
these are at least partially covered in proposed pr 1545 with the suggested result-and-then/maybe-and-then |
These macros each thread the value of a Maybe or Result through
subsequent forms only when the Maybe or Result is a Just/Success value,
returning Nothing/Error otherwise.
It's a convenient way to execute some sequence of forms when a
Maybe/Result returning function is successful, immediately returning the
error value otherwise.
Example: