2016-02-04 21 views
0

我非常簡要地研究一下Scheme,並想知道是否有辦法執行以下操作:向每個結果(#t和#f)添加若干操作。計劃 - 如果結果有多個操作

(if (something) 
    Do something //true, #t 
    Do one thing AND another thing)) //false, #t 

作爲一個例子,給定一個採用整數x的過程。如果它大於五個 - >打印出一條消息。如果小於五 - >打印出的消息和X設置爲零:

(if (> x 5) 
    "Greater than five" 
    "Less than or equal to 5", (= x 0)) 

要改寫:我正在尋找一種機制,允許我做以下(在Java語法表示):

if (cond) { //true 
    //Do this 
} 
else { //false 
    //Do this 
    //AND this 
} 
+3

查看'begin'和'cond'的文檔。 – uselpa

+4

'(= x 0)'不會將'x'設置爲'0'。這將是'(set!x 0)',但你試圖在Scheme中避免這種情況。嘗試找到一個體面的計劃教程,這種語言可能與你習慣的非常不同。 – uselpa

+2

不要嘗試按照其他語言編寫代碼的方式進行逐行轉換 - 您需要將自己從分配和排序中解放出來。免費在線書籍:[SICP](https://www.mitpress.mit.edu/sicp/),[HtDP](http://htdp.org/)。 DrRacket的文檔中還有一個教程。 – molbdnilo

回答

3

隨你去吧!

好的,所以你說我們真的卡住了,你至少知道if給你兩個分支。

(if #t "a" "b") ; => "a" 
(if #f "a" "b") ; => "b" 

"a""b"可以是任何東西,對不對?如果他們是程序呢?

(define (a) "10") 
(define (b) "20") 
(if #t (a) (b)) ; => "10" 
(if #f (a) (b)) ; => "20" 

好的,我們知道過程體可以按順序評估任意數量的表達式。因此,我們可以擴大ab喜歡的東西

(define (a) (print "a is ") (print "10") (newline)) 
(define (b) (print "b is ") (print "20") (newline)) 
(if #t (a) (b)) ; "a is 10\n" 
(if #f (a) (b)) ; "b is 20\n" 

OK所以也許這是一個有點麻煩,你想有一個邏輯分支需要EVAL多個表達式每次定義過程,但至少它的工作原理。然後你可以用lambda表達你的程序,讓你的生活變得更輕鬆

((if #t 
    (λ() 
     (print "a") 
     (print "b") 
     (newline)) 
    (λ() 
     (print "c") 
     (print "d") 
     (newline)))) ; "ab\n" 

((if #f 
    (λ() 
     (print "a") 
     (print "b") 
     (newline)) 
    (λ() 
     (print "c") 
     (print "d") 
     (newline)))) ; "cd\n" 

好吧,現在你不能說你已經被困住了。事情可能看起來與他們在Java中完全一樣(謝天謝地),但至少事情是按照預期行事的。

隨着您繼續學習語言和常用習語,您可能會偶然發現condbegin。他們可能會讓你的生活更輕鬆,但你必須明白,他們沒有什麼神奇的。你可以自己輕鬆實現這些。

你可以彌補一切隨你去。這是我熱愛計劃/拍子的原因之一。沒有任何東西是神聖的/神聖的,你可以基本上實現任何你能想象的東西。

2

儘管如此,if在方案中與algol家族中的if有很大不同。 algol衍生物中的If是分支或條件跳轉指令; if直接改變代碼的流程。在scheme/lisps中,每個if都會返回一個值。由於解釋器或編譯器的內部結構的限制,它不是一個完整的函數,但是對於大多數目的,您可以將它視爲另一個函數。

(if (something) 
    Do something //true, #t 
    Do one thing AND another thing)) //false, #t 

錯了,究竟是怎麼回事。

(if condition 
    (return value of this first exp) //true value 
    (return value or this second exp)) //false value 

在方案中,當你想一個函數有一個副作用,那就是你必須非常明確發生變異的狀態,它的標記是變異狀態用「!」的功能是個好主意在函數名稱的末尾。

程序如set!vector-set!等返回未指定的值。如果您需要特定順序的副作用和特定值或多個副作用,則必須用begin包裝整個事物。另外,如果你只是(set! x 0)你只能改變本地範圍內的x的值,這可能不是你想要做的。不管你使用什麼綁定符號來傳遞函數,它仍然帶有舊值(set-car,v ector-set!set-cell-contents!確實修改了跨越詞法邊界調用的數據結構的基礎狀態)顯式遞歸或在閉包中隱藏值通常是合適的。

begin的語法是(begin exp1 ... expN)Begin依次評估每個表達式,並返回最後一個表達式的值。唯一有用的是,如果所有表達式在最後創建副作用(mutate state或執行I/O)之前。同時請記住definecond的每個子句包含和隱含begin

在Java中,打印字符串的過程會產生副作用。如果不是簡單地返回一個字符串,這是(if (> x 5) ..的第一個分支正在做的事情。

所以爲了簡化事情,我們將保留字符串打印作爲副作用,並將x的下一個或新值作爲語句的返回值。

(cond ((> x 5) (display "Greater than five")  (newline) x) 
     (else (display "Less than or equal to 5") (newline) 0)) 

或幾乎等同

(if (> x 5) 
    (begin (display "Greater than five")  (newline) x) 
    (begin (display "Less than or equal to 5") (newline) 0)) 
1

只需使用begin,這是非常類似λ表達:

(if #t 
    (begin (displayln "Hello, world!") (displayln "wtf")) 
    (displayln "stdio.h")) 

你可以用幾乎任何你想成爲一個begin表達。它們通常用於流量控制,因爲開始時的所有內容都是先評估的,但由於if是一個宏(使用define-syntax而不是define創建),因此它將begin視爲另一個表達式。