-
Notifications
You must be signed in to change notification settings - Fork 34
[210_5] 实现 either-flat-map #696
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
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,5 +1,7 @@ | ||
| # 210_5 | ||
|
|
||
| ## 2026/4/13 实现 either-flat-map | ||
|
|
||
| ## 2026/1/20 修改either的实现方法 | ||
|
|
||
| ## 2026/1/19 开源either相关的代码 | ||
| ## 2026/1/19 开源either相关的代码 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,65 @@ | ||
| (import (liii check) | ||
| (liii error) | ||
| (liii either) | ||
| ) ;import | ||
|
|
||
| (check-set-mode! 'report-failed) | ||
|
|
||
| ;; either-flat-map | ||
| ;; 对 Right 值执行返回 Either 的过程,并避免产生嵌套 Either。 | ||
| ;; | ||
| ;; 语法 | ||
| ;; ---- | ||
| ;; (either-flat-map proc either) | ||
| ;; | ||
| ;; 参数 | ||
| ;; ---- | ||
| ;; proc : procedure? | ||
| ;; 要应用到 Right 值上的函数,返回值应为 Either。 | ||
| ;; | ||
| ;; either : either | ||
| ;; 输入 Either 值。 | ||
| ;; | ||
| ;; 返回值 | ||
| ;; ---- | ||
| ;; either | ||
| ;; 若输入为 Right,则返回 proc 的结果;若输入为 Left,则原样返回。 | ||
| ;; | ||
| ;; 注意 | ||
| ;; ---- | ||
| ;; 对 Left 具有短路特性,不会执行 proc。 | ||
| ;; | ||
| ;; 示例 | ||
| ;; ---- | ||
| ;; (to-right (either-flat-map (lambda (x) (from-right (* x 2))) (from-right 5))) => 10 | ||
| ;; | ||
| ;; 错误处理 | ||
| ;; ---- | ||
| ;; type-error 当 proc 不是过程或 either 不是 Either 时 | ||
|
|
||
| (let ((left-val (from-left "error")) | ||
| (right-val (from-right 5))) | ||
| (check (to-left (either-flat-map (lambda (x) (from-right (* x 2))) left-val)) => "error") | ||
| (let ((result (either-flat-map (lambda (x) (from-right (* x 2))) right-val))) | ||
| (check-true (either-right? result)) | ||
| (check (to-right result) => 10) | ||
| ) ;let | ||
| ) ;let | ||
|
|
||
| (let* ((val1 (from-right 10)) | ||
| (val2 (either-flat-map (lambda (x) (from-right (+ x 5))) val1)) | ||
| (val3 (either-flat-map (lambda (x) (from-right (* x 2))) val2))) | ||
| (check-true (either-right? val3)) | ||
| (check (to-right val3) => 30) | ||
| ) ;let* | ||
|
Comment on lines
+49
to
+54
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
The existing chaining test only covers Right → Right → Right. The key monadic property is that once a step returns ;; Right -> Left -> (short-circuit) -> Left
(let* ((val1 (from-right 7))
(val2 (either-flat-map (lambda (x) (from-left "err")) val1))
(val3 (either-flat-map (lambda (x) (from-right (* x 2))) val2)))
(check-true (either-left? val3))
(check (to-left val3) => "err")
) ;let*would explicitly verify the short-circuit behaviour that is the defining feature of monadic chaining. |
||
|
|
||
| (let ((result (either-flat-map (lambda (x) (from-left (string-append "bad: " (number->string x)))) | ||
| (from-right 7)))) | ||
| (check-true (either-left? result)) | ||
| (check (to-left result) => "bad: 7") | ||
| ) ;let | ||
|
|
||
| (check-catch 'type-error (either-flat-map (lambda (x) (from-right x)) "not-either")) | ||
| (check-catch 'type-error (either-flat-map "not-a-proc" (from-right 10))) | ||
|
|
||
| (check-report) | ||
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.
fnot validatedeither-flat-mapis a monadic bind —fis expected to return anEither. If a caller passes a plain-value function (e.g.(lambda (x) (* x 2))), the result is silently a non-Either, breaking the type invariant for every downstreameither-*call. The error then surfaces with a confusing message in the downstream function rather than here.Contrast with
either-map, which wrapsf's result infrom-rightunconditionally. Forflat-mapthe wrapping is intentionally skipped, so an explicit runtime check is needed instead: