Scheme中的'和'将忽略错误'除以0',如(和(负)(随机100))(/ 1 0))返回#f.它是如何做到的?
i(定义(∧b0 b 1)(if(not b 0)#f b 1)),(∧(负?(随机100))(/ 1 0))仍然进入'除以0'错误.
您不能and直接定义为函数,因为Scheme是严格的 -这意味着函数参数在传递给函数之前总是被计算.
但是,您可以and使用宏定义适当的短路.这是Racket中最简单的版本:
(define-syntax-rule (my-and a b) (if a b #f))
Run Code Online (Sandbox Code Playgroud)
或syntax-rules标准计划中使用的等效表格:
(define-syntax my-and
(syntax-rules ()
[(_ a b) (if a b #f)]))
Run Code Online (Sandbox Code Playgroud)
宏不是正常的功能.相反,它是一个在编译时运行的语法转换.当您and在代码中使用new 时,它会"扩展"到相应的if表达式.所以:
(my-and #f (/ 1 0))
Run Code Online (Sandbox Code Playgroud)
变成了
(if #f (/ 1 0) #f)
Run Code Online (Sandbox Code Playgroud)
在程序运行之前.由于if内置于语言中,因此具有正确的行为.
由于宏不是函数,它也意味着你不能作为参数传递.所以你不能and直接使用折叠- 你必须将它包装成lambda.
为了更忠实于原始and,你可以定义my-and通过使宏递归来获取任意数量的参数.要在宏中定义"rest参数",请使用special ...关键字:
(define-syntax my-and
(syntax-rules ()
[(_) #t]
[(_ a) a]
[(_ a b ...) (if a (my-and b ...) #f)]))
Run Code Online (Sandbox Code Playgroud)
如果你使用像Racket #lang lazy或Haskell 这样的惰性语言,那么你不需要在这里使用宏.您可以直接定义and:
#lang lazy
(define (and a b) (if a b #f))
Run Code Online (Sandbox Code Playgroud)
或者在Haskell:
and a b = if a then b else False
Run Code Online (Sandbox Code Playgroud)
并且它将具有正确的行为,作为正常功能.你可以将它传递and给折叠,它甚至会在遇到它时立即停止评估列表False!看一看:
Prelude> foldl and True [True, False, error "fail"]
False
Run Code Online (Sandbox Code Playgroud)
(error在Haskell中出错就像1/0.因为Haskell是静态类型的,所以and必须是booleans 的参数,所以你不能1/0直接使用.)
| 归档时间: |
|
| 查看次数: |
388 次 |
| 最近记录: |