On this page:
3.9.1 Maybe类型定义
Maybe/  c
Just
Nothing
nothing
3.9.2 操作
maybe?
->maybe
maybe-filter
maybe-and
maybe-or
maybe-alt
maybe-else
maybe->
maybe-just
maybe-unwrap
maybe-catch
3.9.3 Maybe的do记法
maybe/  do
8.12

3.9 Maybe🔗

Nil的安全类型,在类型上避免空指针错误。

3.9.1 Maybe类型定义🔗

procedure

(Maybe/c a)  contract?

  a : any/c
“泛型”maybe容器,检测Just是否为a。

procedure

(Just a)  (Maybe/c any/c)

  a : any/c
(Nothing)  (Maybe/c any/c)
Maybe构造器。 同时可用于match

value

nothing : (Maybe/c any/c)

已确定的Maybe的值。无须再调用生成。

3.9.2 操作🔗

procedure

(maybe? x)  boolean?

  x : any/c
检测是否Maybe。

procedure

(->maybe x)  (Maybe/c x)

  x : any/c
将任意一个值转化成Maybe。Racket不像其他语言有个特殊的Nil,它用#f表示“空”, 因此该函数仅会将#f转化为nothing,其他一切都为Just

这引来一个问题,那么我们该如何得到Just #f呢?我的答案是直接调用(Just #f)

Examples:
> (->maybe 1)

(Just 1)

> (->maybe 0)

(Just 0)

> (->maybe #f)

(Nothing)

> (Just #f)

(Just #f)

> (->maybe #t)

(Just #t)

procedure

(maybe-filter f ma)  (Maybe/c a)

  f : (-> a boolean?)
  ma : (Maybe/c a)
类似于filterf返回#f,整个结果就成了nothing

Examples:
> (maybe-filter even? (Just 2))

(Just 2)

> (define (gt xs)
          (> (length xs) 5))
> (maybe-filter gt (Just (array 1 2 3)))

(Nothing)

> (maybe-filter gt (Just (array 1 2 3 4 5 6)))

(Just (Array 1 2 3 4 5 6))

procedure

(maybe-and ma mb)  (Maybe/c)

  ma : (Maybe/c any/c)
  mb : (Maybe/c)
类似于andmamb其中之一是nothing,结果就是nothing,反之返回mb

Examples:
> (maybe-and (Just 1) nothing)

(Nothing)

> (maybe-and (Nothing) (Just 2))

(Nothing)

> (maybe-and (Just 1) (Just 2))

(Just 2)

procedure

(maybe-or ma mb)  (Maybe/c any/c)

  ma : (Maybe/c any/c)
  mb : (Maybe/c any/c)
类似于or。见maybe-and

Examples:
> (maybe-or (Just 1) nothing)

(Nothing)

> (maybe-or (Nothing) (Just 2))

(Nothing)

> (maybe-or (Just 1) (Just 2))

(Just 1)

procedure

(maybe-alt ma mb)  (Maybe/c any/c)

  ma : (Maybe/c any/c)
  mb : (Maybe/c any/c)
只有当mamb都为nothing,结果才为nothing

Examples:
> (maybe-alt (Just 1) (Just 2))

(Just 1)

> (maybe-alt (Just 1) (Nothing))

(Just 1)

> (maybe-alt nothing (Just 2))

(Just 2)

procedure

(maybe-else a f ma)  any/c

  a : any/c
  f : (-> any/c any/c)
  ma : (Maybe/c any/c)
根据条件选择对应的回调函数:Just调用fnothing则返回a

Examples:
> (maybe-else 10 add1 (Just 1))

2

> (maybe-else 10 add1 nothing)

10

procedure

(maybe-> x f)  (or/c x any/c)

  x : any/c
  f : (Maybe/c any/c)
maybe,接受一个默认值x,如果fJust,则直接获取Just内容,反之以x代之。

Examples:
> (maybe-> 1 nothing)

1

> (maybe-> 1 (Just 2))

2

procedure

(maybe-just msg x)  a

  msg : string?
  x : (Maybe/c a)
解包Maybe,遇到nothing抛异常,异常信息为msg

Examples:
> (maybe-just "这里不会显示" (Just 1))

1

> (maybe-just "我不能啊" (Nothing))

我不能啊

procedure

(maybe-unwrap x)  y

  x : (Maybe/c y)
解包Maybe,遇到nothing直接抛异常。

Examples:
> (maybe-unwrap (Just 1))

1

> (maybe-unwrap (Just #f))

#f

> (maybe-unwrap nothing)

maybe-unwrap: 试图解包nothing!

语法

(maybe-catch expr)

 
expr = 任何表达式
自动捕获expr错误,如果expr无任何错误,返回"(Just expr)",反之返回nothing

Examples:
> (maybe-catch (* 1 0))

(Just 0)

> (maybe-catch (/ 1 0))

(Nothing)

3.9.3 Maybe的do记法🔗

syntax

(maybe/do expr ...+)

 
expr = 普通表达式
  | 赋值表达式
  | 中断表达式
  | 副作用表过式
     
赋值表达式 = 
  | (let id = expr)
  | (id <- expr)
     
中断表达式 = 
  | (break)
  | (break )
     
副作用表过式 = 
  | (! 任意表达式 ...+)
自动处理空值语法,无论何种方式,经过maybe/do的结果必然是maybe?

在赋值表达式中,(id <- expr)这种形式,会对expr结果进行封装,如果是普通值(非Maybe),会以->maybe包装后再进行相关流程。(let)表达式就是纯粹赋值,没有多余处理流程。

Examples:
> (define (f n)
    (and (< n 5) n))
> (maybe/do
    (a <- (f 1))
    (b <- (f 2))
    (+ a b))

(Just 3)

> (maybe/do
    (a <- (f 1))
    (b <- (f 10))
    (+ a b))

(Nothing)

> (maybe/do
    (let a = (f 1))
    (let b = (f 10))
    (+ a b))

+: contract violation

  expected: number?

  given: #f

break可以中断操作,提前跳转整个代码块。它可以接受一个参数或无参数:接受一个参数,该参数自动封装成maybe?(除非已经是Maybe);无参数返回nothing

Examples:
> (maybe/do
    (a <- 1)
    (when (= a 1) (break 10))
    (! (displayln a))
    (add1 a))

(Just 10)

> (maybe/do
    (a <- 1)
    (unless (= a 10) (break))
    a)

(Nothing)

!仅仅用来处理副作用的代码。需要IO处理(如打印、读写文件),又不想中断整个操作,那么可以使用该形式表过式。不管它最终结果是什么,都不会中断后面代码!

Examples:
> (define (fmt x)
    (displayln x)
    #f)
> (maybe/do
    (a <- "hello")
    (b <- "world")
    (! (fmt a)
       (fmt b))
    (void))

hello

world

(Just #<void>)

> (maybe/do
    (a <- "hello")
    (b <- "world")
    (fmt a)
    (fmt b)
    (void))

hello

(Nothing)