4

我是球拍新手,遇到了一个需要可变数值变量的实例

下面是一个通过一串位(101011 ....)工作的函数,如果遇到 1 会更改名为“value”的数字变量,如果遇到 0 则必须更改相同的变量“value”。因此,当我们到达一个字符串的末尾时,我们应该以“值”的总和结束。

(define (implode bstr value)
        (for ([c (string-length bstr)])
           (display (string-ref bstr c))
      (if (eqv? (string-ref bstr c) #\1) (displayln (+ (/ value 3) 17))
          (displayln (/ value 3)))))

如果没有 mtauble 变量,我如何在 prgram 运行时更改此变量?

4

3 回答 3

6

球拍支持突变。例如:

#lang racket

;; count-whales: (listof string) -> number
;; Returns a count of the number of whales in lst.
(define (count-whales lst)
  (define c 0)
  (for ([thing lst])
    (when (equal? thing "shamu")
      (set! c (add1 c))))
  c)

;; Example:
(count-whales '("shamu" "donald duck" "shamu"))

您可能习惯于以这种方式查看循环,其中变异允许我们记录一些运行值。使用突变进行写作没有障碍。但话虽如此,上述功能并不是惯用的球拍。Racketeer 将改为使用可以累积值的循环,而不是使用突变。

以下是使用累加器编写上述函数时的样子:

#lang racket

;; count-whales: (listof string) -> number
;; Returns a count of the number of whales in lst.
(define (count-whales lst)
  (for/fold ([c 0])
            ([thing lst])
    (if (equal? thing "shamu")
        (add1 c)
        c)))

;; Example:
(count-whales '("shamu" "donald duck" "shamu"))
于 2012-12-17T21:27:09.943 回答
5

正如已经建议的那样,这个问题可以很容易地使用递归来解决,而无需使用可变变量。这是在 Scheme 中编写过程的首选方式:

(define (implode bstr value)
  (let loop ((value value)
             (lst (string->list bstr)))
    (cond ((null? lst)
           value)
          ((char=? (car lst) #\1)
           (loop (+ (/ value 3) 17) (cdr lst)))
          ((char=? (car lst) #\0)
           (loop (/ value 3) (cdr lst)))
          (else (error "unexpected char" (car lst))))))
于 2012-12-16T04:42:52.447 回答
4

我不确定该implode功能的目标是什么,但是是的,您绝对不需要使用突变。Racket 是一种高级语言,具有尾调用消除功能,这意味着通过 Óscar 示例中所做的本地函数循环是编译器稍后将转换为使用突变或任何需要的有效代码的东西。

但更重要的是,展示如何编写更简洁的 Racket 代码可能更接近突变的心理模型。这里的主要成分是for/fold,它正在执行“for 循环”,但在整个循环中使用“状态变量”。这里引用了“状态”,因为它实际上并不存在——它实际上是一个宏,可以扩展为与 Óscar 示例中类似的循环。我还以一些小而有用的方式改进了代码的其他部分:您可以直接迭代字符串,不需要索引;那里并不真正需要,但它使in-string迭代更明确,使其更快,并且如果bstr不是字符串则会抛出错误;您可以使用case检查您所在的角色;只要你使用它,如果一个字符既不是“0”也不是“1”,最好抛出一个错误。

这是它的样子:

(define (implode bstr)
  (for/fold ([value 0]) ([c (in-string bstr)])
    (case c
      [(#\0) (+ (/ value 3) 17)]
      [(#\1) (/ value 3)]
      [else (error 'implode "bad character: ~e" c)])))

尽管如此,这会产生一些奇怪的结果,但同样,我不确定这个函数应该做什么......

于 2012-12-16T04:58:39.863 回答