Lisp中的选项类型编码/健壮性

2 lisp functional-programming robustness maybe option-type

(define (nth n lst)
  (if (= n 1)
    (car lst)
    (nth (- n 1)
         (cdr lst) )))
Run Code Online (Sandbox Code Playgroud)

是一个不安全的部分功能,n可能会超出范围.一个error可以帮助,

(define (nth n lst)
  (if (null? lst)
    (error "`nth` out of range")
    (if (= n 1)
      (car lst)
      (nth (- n 1)
           (cdr lst) ))))
Run Code Online (Sandbox Code Playgroud)

但是,与Haskell 数据类型类似的强大 Scheme Maybe类似于什么呢?

data Maybe a = Nothing | Just a

nth :: Int -> [a] -> Maybe a
nth _ []       = Nothing
nth 1 (x : _)  = Just x
nth n (_ : xs) = nth (n - 1) xs
Run Code Online (Sandbox Code Playgroud)

刚刚回来了'()吗?

(define (nth n lst)
  (if (null? lst) '()
    (if (= n 1)
      (car lst)
      (nth (- n 1)
           (cdr lst) ))))
Run Code Online (Sandbox Code Playgroud)

8bi*_*ree 6

打破你的尝试很容易.只需创建一个包含空列表的列表:

(define lst '((1 2) () (3 4)))
(nth 2 lst)
-> ()
(nth 100 lst)
-> ()
Run Code Online (Sandbox Code Playgroud)

你缺少的关键点是Haskell Maybe不仅仅在它存在时返回一个裸值,它包含了这个值.正如你所说,Haskell定义Maybe如下:

data Maybe a = Nothing | Just a
Run Code Online (Sandbox Code Playgroud)

喜欢这样:

data Maybe a = Nothing | a
Run Code Online (Sandbox Code Playgroud)

后者相当于你正在做的事情.

要获得正确的大部分,Maybe如果元素不存在,您可以返回一个空列表,如果元素确实存在,还可以将返回值包装在另一个列表中:

(define (nth n lst)
  (if (null? lst) '()
    (if (= n 1)
      (list (car lst)) ; This is the element, wrap it before returning.
      (nth (- n 1)
           (cdr lst) ))))
Run Code Online (Sandbox Code Playgroud)

这样,您的结果将是一个空列表,意味着该元素不存在,或者一个列表只包含一个元素:您要求的元素.重用上面的相同列表,我们可以区分空列表和不存在的元素:

(define lst '((1 2) () (3 4)))
(nth 2 lst)
-> (())
(nth 100 lst)
-> ()
Run Code Online (Sandbox Code Playgroud)