<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??一站式輕松地調用各大LLM模型接口,支持GPT4、智譜、豆包、星火、月之暗面及文生圖、文生視頻 廣告
                [TOC=2] ## 10.1?簡介 因為Scheme是函數式語言,通常來說,你可以編寫不使用賦值的語句。然而,如果使用賦值的話,有些算法就可以輕易實現了。尤其是內部狀態和**繼續(continuations )**需要賦值。 盡管賦值非常習見并且易于理解,但它有一些本質上的缺陷。參見《計算機程序的構造和解釋》的第三章第一節“賦值和局部狀態”以及《為什么函數式編程如此重要》 R5RS中規定的用于賦值的特殊形式是`set!`、`set-car!`、`set-cdr!`、`string-set!`、`vector-set!`等。除此之外,有些實現也依賴于賦值。由于賦值改變了參數的值,因此它具有**破壞性(destructive)**。Scheme中,具有破壞性的方法都以`!`結尾,以警示程序員。 ## 10.2?set! `set!`可以為一個參數賦值。與Common Lisp不同,`set!`無法給一個S-表達式賦值。 賦值前參數應被定義。 ~~~ (define var 1) (set! var (* var 10)) var ? 10 (let ((i 1)) (set! i (+ i 3)) i) ? 4 ~~~ ## 10.3?賦值和內部狀態 ### 10.3.1?靜態作用域(詞法閉包) Scheme中變量的作用域被限定在了源碼中定義其的那個括號里。作用域與源代碼書寫方式一致的作用域稱為**“詞法閉包(Lexical closure)”**或**“靜態作用域(Static scope)”**。This way of scope eliminates bags, as you can grasp the scope of parameters quite easily — written on the source code.另一方面,還有一種被稱為**“動態作用域(Dynamic scope)”**的作用域。這種作用域僅在程序運行時確定。由于會在調試時帶來種種問題,這種作用域現在已經不再使用。 特殊形式`let`、`lambda`、`letrec`生成閉包。lambda表達式的參數僅在函數定義內部有效。`let`只是`lambda`的語法糖,因此二者無異。 ### 10.3.2?使用賦值和詞法閉包來實現內部狀態 你可以使用詞法閉包來實現帶有內部狀態的過程。例如,用于模擬銀行賬戶的過程可以按如下的方式編寫:初始資金是10美元。函數接收一個整形參數。正數表示存入,負數表示取出。為了簡單起見,這里允許存款為負數。 ~~~ (define bank-account (let ((balance 10)) (lambda (n) (set! balance (+ balance n)) balance))) ~~~ 該過程將存款賦值為`(+ balance n)`。下面是調用這個過程的結果。 The procedure assigns?(+ balance n)?to the?balance.??Following is the result of calling this function. ~~~ (bank-account 20) ; donating 20 dollars ;Value: 30 (bank-account -25) ; withdrawing 25 dollars ;Value: 5 ~~~ 因為在Scheme中,你可以編寫返回過程的過程,因此你可以編寫一個創建銀行賬戶的函數。這個例子喻示著使用函數式程序設計語言可以很容易實現面向對象程序設計語言。實際上,只需要在這個基礎上再加一點東西就可以實現一門面向對象程序設計語言了。 ~~~ (define (make-bank-account balance) (lambda (n) (set! balance (+ balance n)) balance)) (define gates-bank-account (make-bank-account 10)) ; Gates makes a bank account by donating 10 dollars ;Value: gates-bank-account (gates-bank-account 50) ; donating 50 dollars ;Value: 60 (gates-bank-account -55) ; withdrawing 55 dollars ;Value: 5 (define torvalds-bank-account (make-bank-account 100)) ; Torvalds makes a bank account by donating 100 dollars ;Value: torvalds-bank-account (torvalds-bank-account -70) ; withdrawing 70 dollars ;Value: 30 (torvalds-bank-account 300) ; donating 300 dollars ;Value: 330 ~~~ ### 10.3.3?副作用 Scheme過程的主要目的是返回一個值,而另一個目的則稱為**副作用(Side Effect)**。賦值和IO操作就是副作用。 > 練習 1 > > 修改make-bank-account函數 Modify?make-bank-account?so that withdrawing more than balance causes error.?> hint: Use?begin?to group more than one S-expressions. ## 10.4?表的破壞性操作(set-car!,set-cdr!) 函數set-cat!和set-cdr!分別為一個cons單元的car部分和cdr部分賦新值。和set!不同,這兩個操作可以為S-表達式賦值。 ~~~ (define tree '((1 2) (3 4 5) (6 7 8 9))) (set-car! (car tree) 100) ; changing 1 to 100 tree ((100 2) (3 4 5) (6 7 8 9)) (set-cdr! (third tree) '(a b c)) ; changing '(7 8 9) to '(a b c) tree ? ((100 2) (3 4 5) (6 a b c)) ~~~ ### 10.4.1?隊列 隊列可以用set-car!和set-cdr!實現。隊列是一種**先進先出(First in first out, FIFO)**的數據結構,表則是**先進后出(First in last out,FILO)**。圖表1展示了隊列的結構。`cons-cell-top`的car部分指向表(頭),而(`cons-cell-top`的)cdr部分指向表末的cons單元(表尾)。 入隊操作按如下步驟進行(見圖表2): 1\. 將當前最末的cons單元(可以通過`cons-cell-top`取得)的cdr部分重定向到新的元素。 2\. 將`cons-cell-top`的cdr部分重定向到新的元素 出隊操作按如下步驟進行(見圖表3) 1\. 將隊首元素存放在一個局部變量里。 2\. 將`cons-cell-top`的car部分重定向到表的第二個元素 [代碼片段1]展示了如何實現隊列。函數enqueue!返回將元素obj添加進隊列queue后的隊列。函數dequeue!將隊列的首元素移出隊列并將該元素的值作為返回值。 [代碼片段1] 隊列的Scheme實現 ~~~ (define (make-queue) (cons '() '())) (define (enqueue! queue obj) (let ((lobj (cons obj '()))) (if (null? (car queue)) (begin (set-car! queue lobj) (set-cdr! queue lobj)) (begin (set-cdr! (cdr queue) lobj) (set-cdr! queue lobj))) (car queue))) (define (dequeue! queue) (let ((obj (car (car queue)))) (set-car! queue (cdr (car queue))) obj)) (define q (make-queue)) ;Value: q (enqueue! q 'a) ;Value 12: (a) (enqueue! q 'b) ;Value 12: (a b) (enqueue! q 'c) ;Value 12: (a b c) (dequeue! q) ;Value: a q ;Value 13: ((b c) c) ~~~ ## 10.5?小結 這一章中,我講解了賦值和變量的作用域。雖然在Scheme中,賦值并不常用,但它對于某些算法和數據結構來說是必不可少的。濫用賦值會讓你的代碼丑陋。當萬不得已時才使用賦值!在后面的幾章里,我會介紹Scheme中的數據結構。 ## 10.6?習題解答 ### 10.6.1?練習1 ~~~ (define (make-bank-account amount) (lambda (n) (let ((m (+ amount n))) (if (negative? m) 'error (begin (set! amount m) amount))))) ~~~
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看