Skip to content

Commit cdb48fe

Browse files
authored
[210_5] 实现 either-flat-map (#696)
1 parent a09f8a6 commit cdb48fe

4 files changed

Lines changed: 85 additions & 2 deletions

File tree

devel/210_5.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
# 210_5
22

3+
## 2026/4/13 实现 either-flat-map
4+
35
## 2026/1/20 修改either的实现方法
46

5-
## 2026/1/19 开源either相关的代码
7+
## 2026/1/19 开源either相关的代码

goldfish/liii/either.scm

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
from-right to-right
2121
either? ; 导出通用判断函数
2222
either-left? either-right?
23-
either-map either-for-each
23+
either-map either-flat-map either-for-each
2424
either-get-or-else
2525
either-or-else
2626
either-filter-or-else
@@ -122,6 +122,21 @@
122122
) ;if
123123
) ;define
124124

125+
;; 扁平映射函数:如果 either 是右值,则应用返回 Either 的函数 f
126+
(define (either-flat-map f either)
127+
(check-either either "either-flat-map")
128+
(unless (procedure? f)
129+
(type-error (format #f "In function either-flat-map: argument *f* must be *procedure*! **Got ~a**" f))
130+
) ;unless
131+
(if (either-right? either)
132+
(let ((result (f (to-right either))))
133+
(check-either result "either-flat-map: return value of f must be an Either")
134+
result
135+
) ;let
136+
either
137+
) ;if
138+
) ;define
139+
125140
;; 遍历函数:如果 either 是右值,则应用函数 f (执行副作用)
126141
(define (either-for-each f either)
127142
(check-either either "either-for-each")

tests/liii/either-test.scm

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
;; 三、高阶操作
3939
;; 用于映射、遍历和过滤 Either 的函数
4040
;; either-map - 仅对 Right 中的值进行映射
41+
;; either-flat-map - 对 Right 执行返回 Either 的链式操作
4142
;; either-for-each - 仅对 Right 中的值执行副作用
4243
;; either-filter-or-else - 不满足条件时回退到 Left
4344
;; either-contains? - 判断 Right 中的值是否满足目标
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
(import (liii check)
2+
(liii error)
3+
(liii either)
4+
) ;import
5+
6+
(check-set-mode! 'report-failed)
7+
8+
;; either-flat-map
9+
;; 对 Right 值执行返回 Either 的过程,并避免产生嵌套 Either。
10+
;;
11+
;; 语法
12+
;; ----
13+
;; (either-flat-map proc either)
14+
;;
15+
;; 参数
16+
;; ----
17+
;; proc : procedure?
18+
;; 要应用到 Right 值上的函数,返回值应为 Either。
19+
;;
20+
;; either : either
21+
;; 输入 Either 值。
22+
;;
23+
;; 返回值
24+
;; ----
25+
;; either
26+
;; 若输入为 Right,则返回 proc 的结果;若输入为 Left,则原样返回。
27+
;;
28+
;; 注意
29+
;; ----
30+
;; 对 Left 具有短路特性,不会执行 proc。
31+
;;
32+
;; 示例
33+
;; ----
34+
;; (to-right (either-flat-map (lambda (x) (from-right (* x 2))) (from-right 5))) => 10
35+
;;
36+
;; 错误处理
37+
;; ----
38+
;; type-error 当 proc 不是过程或 either 不是 Either 时
39+
40+
(let ((left-val (from-left "error"))
41+
(right-val (from-right 5)))
42+
(check (to-left (either-flat-map (lambda (x) (from-right (* x 2))) left-val)) => "error")
43+
(let ((result (either-flat-map (lambda (x) (from-right (* x 2))) right-val)))
44+
(check-true (either-right? result))
45+
(check (to-right result) => 10)
46+
) ;let
47+
) ;let
48+
49+
(let* ((val1 (from-right 10))
50+
(val2 (either-flat-map (lambda (x) (from-right (+ x 5))) val1))
51+
(val3 (either-flat-map (lambda (x) (from-right (* x 2))) val2)))
52+
(check-true (either-right? val3))
53+
(check (to-right val3) => 30)
54+
) ;let*
55+
56+
(let ((result (either-flat-map (lambda (x) (from-left (string-append "bad: " (number->string x))))
57+
(from-right 7))))
58+
(check-true (either-left? result))
59+
(check (to-left result) => "bad: 7")
60+
) ;let
61+
62+
(check-catch 'type-error (either-flat-map (lambda (x) (from-right x)) "not-either"))
63+
(check-catch 'type-error (either-flat-map "not-a-proc" (from-right 10)))
64+
65+
(check-report)

0 commit comments

Comments
 (0)