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)

      )
)

次に、結果に応じて、true または false を返します。しかし、リストを反復処理する方法がわかりません。リストを文字列に変換して文字列関数を使用したくありません。「foreach」や for loop のようなステートメントはありますか? または他の提案はありますか?

注:車を使用してから取り外して残りのリストを見ることも考えましたが、長さがわからないため、車を何回使用するか、つまり車にする必要があるかどうかはわかりません。カー、カー、など。

ありがとうございました

4

4 に答える 4

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 を学ぶにつれて、再帰を活用する機会を探すことで利益が得られます。

于 2013-04-30T14:03:38.787 に答える
2

まず、引数が長さ 1 のシンボルの場合に true を返し、それ以外の場合に false を返すラムダを考えてみましょう。

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

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

文字列表現を除いて、シンボル'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
于 2013-04-30T13:42:41.910 に答える
2

A simple way, using readily available functions - in particular, you could use andmap in Racket (or for-all in R6RS, or every in SRFI-1); think of it as a foreach that returns #t if all the elements in a list satisfy a predicate. This solution is more in line with the spirit of functional programming, in the sense that it uses generic, higher-order procedures to solve a new problem by combining existing solutions to other subproblems. In other words, we don't reinvent the wheel:

(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))

Notice how the code says exactly what it means: a list is a "sequence" if it's true, for all of its elements, that each one is a symbol of length one. To determine a symbol's length, we convert it first into a string, which we can easily check to see if it meets the length requirement. It works as expected:

(sequence? '(a b c))
=> #t
(sequence? '(aa b c))
=> #f
(sequence? '(a 1 c))
=> #f
(sequence? '(a (b c)))
=> #f
于 2013-04-30T13:53:26.900 に答える
2

「foreach」や for loop のようなステートメントはありますか?

いいえ。

または他の提案はありますか?

スキームでリストを反復処理するには、リストを反復処理する既存の関数 ( mapfilterまたは などfold-left) を使用するか、再帰を使用して独自の関数を記述します。使用しているScheme方言によっては、リストと条件を受け取り、リスト内のすべての項目について条件が真である場合に返す関数( everyorと呼ばれる)がすでに存在する場合があります。それ以外の場合は、再帰的に、または折り畳みとして記述する必要があります (ただし、Scheme の方言のすべてに折り畳み機能があるわけではありません)。andmap#t

リストを反復処理する再帰関数は通常、次のようになります。

(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 より大きいすべての数値を ( filterorを使用せずにfold-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がブール値以外であり、それをブール値に変換する必要がある場合を除きますが、それが必要なシナリオは考えられません)。

于 2013-04-30T13:43:22.787 に答える