简体   繁体   English

如何在Dr.Racket中重新分配值

[英]How to reassign value in Dr.Racket

I am trying to implement Binary Tree in Scheme-Dr.Racket, but i have some trouble with the insert! 我正在尝试在Scheme-Dr.Racket中实现Binary Tree,但是我在插入时遇到了一些麻烦! function. 功能。

Here is the source 这是来源

(define (makeTree leftSubTree root rightSubTree)
  (list leftSubTree root rightSubTree))

(define (subTree part tree)
  (if (null? tree)
      '()
      (part tree)))

(define (root tree)
  (subTree cadr tree))

(define (leftSubTree tree)
  (subTree car tree))

(define (rightSubTree tree)
  (subTree caddr tree))

(define (leaf? tree)
  (and (null? (leftSubTree tree))
       (null? (rightSubTree tree))))

; (define tree (makeTree (makeTree '() 1 '()) 2 (makeTree '() 3 '()))) 

(define (member? tree element)
  (if (null? tree)
      #f
      (or (= (root tree) element)
          (member? (leftSubTree tree) element)
          (member? (rightSubTree tree) element))))

(define (insert! tree element)
  (if (null? tree)
      (set! tree (makeTree '() element '()))
      (if (leaf? tree)
          (cond
            ((> (root tree) element) (set! tree (makeTree (makeTree '() element '()) (root tree) '())))
            ((< (root tree) element) (set! tree (makeTree '() (root tree) (makeTree '() element '()))))
            ((= (root tree) element) '()))
          (cond
            ((= (root tree) element) '())
            ((> (root tree) element) (insert! (leftSubTree tree) element))
            (else  (insert! (rightSubTree tree) element))))))

As far as I know the set! 据我所知! function changes the value of the object id is pointing to or 函数更改指向或指向的对象id的值

(set! tree (makeTree '() val '()))

Is going to change the value of tree to a tree with one node - val. 将把树的值更改为具有一个节点的树-val。 Can someone try to explain me why am i wrong? 有人可以解释我为什么我错了吗?

Your insert! 您的insert! function only ever affects the binding of its own parameter named tree . 函数仅影响自己名为tree 的参数的绑定。

When the function returns, its parameters' bindings are destroyed with it. 当函数返回时,其参数的绑定随之被破坏。

You want to affect the change to the structure of a memory object your parameter tree refers to. 您想影响参数tree引用的存储对象结构的更改。 That's not what set! 那不是什么set! does. 确实。 It only changes the value of a variable's binding. 它仅更改变量绑定的值。

In Scheme there's set-car! 在Scheme中有set-car! and set-cdr! set-cdr! primitives for that, but Racket's lists are immutable. 原语,但是Racket的列表是不可变的。 Mutable lists are created with mcons , not with cons , nor list . 可变列表是使用mcons创建的,而不是使用conslist Racket doesn't even have set-car! 球拍甚至没有set-car! and friends, and calls them set-mcar! 和朋友,并称他们为set-mcar! etc. instead, and they don't work on lists created with list . 等等,它们不适用于使用list创建的list

You could switch your tree representation from lists to structs, using define-struct for that. 您可以使用define-struct将树的表示形式从列表切换为结构。

Alternatively, choose an appropriate #lang directive to place at the start of your source file, like eg #lang r5rs so set-car! 或者,选择适当的#lang指令放置在源文件的开头,例如#lang r5rs so set-car! etc. work; 等工作; or create your lists with mcons so you can use set-mcar! 或使用mcons创建列表,以便可以使用set-mcar! and the like, if working under #lang racket : 如果在#lang racket下工作:

> (define y (mcons 1 (mcons 2 '())))
> y
(mcons 1 (mcons 2 '()))
> (set-mcar! y 11)
> y
(mcons 11 (mcons 2 '()))

What is wrong? 怎么了?

Imagine this C-code: 想象一下这个C代码:

void test (int n) {
  n = 6;
}

int v = 1;
test(v);
printf("%d", v)

Now according to your Scheme code you expect 6 to be the printed value, but that is not what happens. 现在,根据您的“方案”代码,您希望6为印刷价值,但事实并非如此。 n is a local variable in test in the same manner as tree is a local variable in insert! ntest中的局部变量,就像treeinsert!的局部变量一样insert! . When you set! 当你set! you are not mutating the value but you redirect what the identifier should point to to a new (perhaps unrelated) value. 您不是要更改值,而是将标识符应指向的内容重定向到新的(也许不相关的)值。 All other bindings point to the same value will still point to the original value since it's the binding n that is changed and not v . 所有其他指向相同值的绑定仍将指向原始值,因为更改的是绑定n而不是v

How to fix it 如何修复

The best is to not mutate at all. 最好是根本不变异。

(define (insert tree element)
  (if (tree-empty? tree)
      (make-tree tree-empty element tree-empty)
      (let ((value (tree-value tree))
            (left (tree-left tree))
            (right (tree-right tree)))
        (if (< value element)
            (make-tree (insert left element) value right)
            (make-tree left value (insert right element))))))

You can still replace a binding like this: 您仍然可以像这样替换绑定:

(set! root (insert root 2))

You can mutate the nodes.. This makes you tree singleton and you need to handle an empty root specially since you cannot mutate null into a value. 您可以对节点进行突变。这使您的树成为单例,并且由于无法将null突变为值,因此需要特别处理空根。 A solution can be a special root with a empty indication. 解决方案可以是带有空指示的特殊根。

(define tree-left-place values)
(define tree-right-place cddr)
(define tree-value-place cdr)
(define +root-value (list 'root))
(define root (make-tree tree-empty %root-value tree-empty))
(define (insert! tree element)
  (define (insert-helper place)
    (if (tree-empty? (place-value place))
        (set-car! place (make-tree empty-tree element empty-tree))
        (insert! (place-var place) element)))

  (let ((value (tree-value tree)))
    (cond ((eq? value +root-value) (set-car! (tree-value-place tree) element))
          ((< element value) (insert-helper (tree-left-place tree)))
          (else (insert-helper (left-right-place tree))))))

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM