为什么在Racket中具有类似goto的功能?

时间:2016-09-28 12:38:52

标签: scheme racket

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的功能吗?

2 个答案:

答案 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可能对继续,解析和编译感兴趣。