-
Notifications
You must be signed in to change notification settings - Fork 178
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: add maybe and result thread macros #1403
base: master
Are you sure you want to change the base?
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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Cool!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's a typo here: erorr
.
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))) |
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: