Racket是一种高级功能语言。但是,似乎名为let的构造允许类似goto的功能并允许编写类似意大利面条的代码:
(define i 1)
(let mylabel ()
(set! i (add1 i))
(println "Doing something...")
(when (even? i)
(println "going to mylabel because i is even")
(mylabel) )
(when (= 0 (modulo i 3))
(println "going to mylabel because i is divisible by 3")
(mylabel) )
(println "Doing something more ...")
(when (= i 7)
(println "going to mylabel because i is 7")
(mylabel) )
(when (> i 10)
(println "ending because i is 10")
)
(println i)
)
这不是包含goto的功能吗?
答案 0 :(得分:5)
命名let只是一个快捷方式,用于定义递归函数,然后立即调用它。如果此功能不存在,您只需将(let mylabel ()
替换为(define (mylabel)
,然后在定义后添加(mylabel)
即可调用它。这将表现完全相同。
因此,命名的let功能不会增加任何类似意大利面条的控制流的潜力,而这种控制流并不仅仅存在于递归函数中。由于绝大多数编程语言都允许递归函数,因此这些语言也存在同样的潜力。
答案 1 :(得分:2)
Racket和Scheme不是纯函数式语言。它们是Common Lisp和所有Algol语言的多范式。
如果该语言纯粹是功能性的,那么你就不会有像set!
这样的感叹号程序,并且在Haskell中会出现像monad这样的东西,使其略显有用。
真实goto
将为call/cc
,这是遵循其中一个报告的方案的要求,与set!
(或任何变异操作符)相结合以获得相同的副作用)。有了它,你可以真正制作不可读的代码:
; The following evaluates to (4 3 5)
(let ((a (amb (list 1 2 3 4 5 6 7)))
(b (amb (list 1 2 3 4 5 6 7)))
(c (amb (list 1 2 3 4 5 6 7))))
; We're looking for dimensions of a legal right
; triangle using the Pythagorean theorem:
(assert (= (* c c) (+ (* a a) (* b b))))
; we would like a to be the largest number
(assert (>= a b))
; this must be it then!
(list a b c))
此代码来自优秀的Matt Mights blog post on call/cc。我已经遗漏了非魔法所以你只看到它的使用方式。它确实看起来像魔术吗?他有multiple articles可能对继续,解析和编译感兴趣。