2013-04-30 36 views
1

我是新來的函數式編程,並試圖寫一個函數,它接受一個列表參數,如果列表包含每個符號的長度爲1的更具體的符號返回true,如何確定輸入是否是計劃中的序列?

;(sequence? '(a b c)) ----> true 
; (sequence? '(aa b c)) ---> false since aa has length 2 
; (sequence? '(a 1 c)) ----> false since 1 is not a symbol 
; (sequence? '(a (b c))) --> false since (b c) is not a symbol 

我的想法執行以下操作:對於列表中的每個符號,我檢查它是否是一個符號,它是長度爲1

(define sequence? 
     (lambda (inSeq) 
     (if (for each item in the list inSeq, all are symbols and length=1) #t #f) 

    ) 
) 

的然後根據結果,我返回真或假。但我不知道如何迭代列表。我不想將列表轉換爲字符串並使用字符串函數。我們是否有像「foreach」這樣的語句,或循環做我的想法?或任何其他建議?

注意:我也考慮過使用汽車,然後將其取下並查看列表的其餘部分,但由於我不知道長度,我不知道應該使用汽車多少次,即是否它應該是汽車,CAAR,caaar等

謝謝

回答

2

如果你已經解決了該列表的第一個元素的問題,那麼你已經解決了它在列表的其餘元件只是重新應用相同的過程中休息。

對於需要進行如下的第一個元素:

(define (is-symbol-1 thing) 
    (and (symbol? thing) 
     (= 1 (string-length (symbol->string thing)))) 

然後

(define (sequence? list) 
    (or (null? list)      ;; #t if list is empty 
     (and (is-symbol-1 (car list)) ;; first element is-symbol-1 
      (sequence? (cdr list))))) ;; and rest is sequence? too 

這是遞歸的一個例子。在您學習Scheme時,您將通過尋找利用遞歸的機會獲益。

+1

謝謝!我不知道如何使用遞歸,現在我明白了 – yrazlik 2013-04-30 17:34:51

2

首先,讓我們弄清楚一個拉姆達將返回true,當它的參數是一個長度的象徵,否則爲false:

(λ (x) (and (symbol? x) (= (string-length (symbol->string x)) 1))) 

;; 'a -> #t, 'aa -> #f, '(a) -> #f 

我們不得不在那裏使用字符串函數,因爲有n o符號'f和符號'foo之間的有意義的區別,除了它們的字符串表示形式。

現在,讓我們採取的拉姆達,並用它來過濾從我們的名單壞分子:

(filter (λ (x) (and (symbol? x) (= (string-length (symbol->string x)) 1))) 
     '(a b c)) 

;; '(a b c) -> '(a b c), '(a 2 c) -> '(a c), '(a bb c) -> '(a c) 

現在,讓我們檢查,以確保沒有被過濾掉,也就是我們原來的列表中的每一個元素是一個長度爲1的符號。我們通過檢查輸出列表的長度與輸入列表的長度是否相同來做到這一點。

(define (symbols-of-length-1 seq) 
    (= (length (filter (λ (x) (and (symbol? x) (= (string-length (symbol->string x)) 1))) 
      seq)) 
    (length seq))) 

;; '(a b c) -> #t, '(a 2 c) -> #f, '(a (b) c) -> #f, '(a bb c) -> #f 
+0

感謝您的回答! – yrazlik 2013-04-30 17:36:38

2

我們有像「的foreach」,或循環做什麼,我想任何聲明?

或任何其他建議?

遍歷在計劃列表中,你要麼使用迭代列表(如mapfilterfold-left)預先存在的功能或者你寫你自己使用遞歸。根據您使用的Scheme方言,可能已經有一個函數(稱爲everyandmap),它接受一個列表和一個條件,並且如果列表中的每個條目的條件爲真,則返回#t。否則,你不得不遞歸地寫成它或作爲一個摺疊(儘管並非所有Scheme方言都具有摺疊功能)。

遞歸函數,在一個列表上循環通常看起來是這樣的:

(define (do-something-with-list lst) 
    (if (null? lst) 
    (handle-the-case-that-list-is-empty) 
    (combine 
     (some-transformation-on (car lst)) 
     (do-something-with-list (cdr lst))))) 

例如總結在大於5列表中的所有號碼(不使用filterfold-left),你會寫:

(define (sum-all-numbers>5 numbers) 
    (if (null? numbers) 
    ; Sum of the empty list is 0 
    0 
    (+ 
     ; If the head of the list is > 5, add the number to the result, else 
     ; add 0 
     (if (> (car numbers) 5) (car numbers) 0) 
     (sum-all-numbers>5 (cdr numbers))))) 

您可以使用相同的方法來定義您的功能。

PS:(if condition #t #f)是多餘的 - 你可以只寫condition(除非condition比其他布爾值的東西,你需要將其轉換成一個布爾值,但我不能想象一個場景的地方是會是必要的)。

+0

感謝您的回答! – yrazlik 2013-04-30 17:35:31

2

一個簡單的方法,使用容易獲得的功能 - 特別是,可以(在SRFI-1或在R6RS for-all,或every)使用在球拍andmap;將其視爲foreach如果列表中的所有元素都滿足謂詞,則返回#t。該解決方案更符合功能編程的精神,因爲它使用通用的高階程序,通過將現有解決方案與其他子問題相結合來解決新問題。換句話說,我們不重新發明輪子:

(define (sequence? seq)  ; `seq` is a sequence if 
    (andmap (lambda (e)  ; it's true for all its elements that 
      (and (symbol? e) ; each element is a symbol 
       (= 1 (string-length (symbol->string e))))) ; with length one 
      seq)) 

注意代碼如何說,到底是什麼意思:一個列表是一個「序列」如果這是真的,它的所有元素,每一個是一個長度的象徵。爲了確定一個符號的長度,我們首先將它轉換成一個字符串,我們可以很容易地檢查它是否符合長度要求。它按預期工作:

(sequence? '(a b c)) 
=> #t 
(sequence? '(aa b c)) 
=> #f 
(sequence? '(a 1 c)) 
=> #f 
(sequence? '(a (b c))) 
=> #f 
+1

如果你的Scheme有它,你只能重用它:) R6RS別名是'for-all' – leppie 2013-04-30 15:12:33

+1

也像@ sepp2k在SRFI-1中說'every' :) http://srfi.schemers.org/srfi-1/ srfi-1.html#正在搜索 – leppie 2013-04-30 16:16:52

+0

確定,已更新;-) – 2013-04-30 16:22:03

相關問題