2017-01-18 7 views
0

リストの最初の数よりも多い数のNUMBER(数)を返すlisp関数を解きたい。リスト線形リストです。LISP FUNCTION - 最初の要素より大きいリストの番号の数を返す

(defun foo (lst) 
    (cond ((null lst) 0) 
     (car = k) 
     ((> (car lst) k) 
     (1+ (foo (cdr lst)))) 
    (T (foo (cdr lst))))) 

私の問題は、最初の要素を保持して他の要素と比較することができないことです。あなたの機能が正しくインデント

+2

あなたはこれまでに何をしようとしたのですか? – coredump

+0

http://clhs.lisp.se/Body/f_countc.htm – coredump

+0

(関数定義のFOO(LST) (COND ((ヌルLST)0) (車= K) ((>(カーLST)K) ()( (foo(cdr lst))))) – SomethingGeneral

答えて

3

は次のようになります。私はあなたの指揮で第二項にコメントしている

(defun foo (lst) 
    (cond ((null lst) 0) 
     (car = k)    ; strange cond term   
     ((> (car lst) k)   
     (1+ (foo (cdr lst)))) 
     (T (foo (cdr lst))))) 

。それはかなり奇妙です。これは、最初の変数car(ない機能#'car)を評価します。 carnilでない場合は、変数=(関数#'=ではない)が最初に評価され、condという用語の最後の結果の式ではないため、最後にkを返します。

第二に、あなたは、しかし、あなたがあなたの関数でkそれを呼び出すが、それはどこにも定義されていない、あなたが比較の最初の要素を使用すると言うことを書きます。あなたは再帰を行う前に、何かをする必要があるので、あなたはそれが最初の要素に、それぞれの時間がかかりますので、実際の関数は再帰をやらせることはできません。ここでは、labelsを使用することができます:

;; didn't call it foo since it's not very descriptive 
(defun count-larger-than-first (list) 
    (let ((first (car list))) 
    (labels ((helper (list) 
       (cond ((null list) 0) 
        ((> (car list) first) 
         (1+ (helper (cdr list)))) 
        (t (helper (cdr list)))))) 
     (helper (cdr list))))) 

もちろんです。 Common Lispではなくて、あなたが本当にそれを書く必要がありますので

(defun count-larger-than-first (list) 
    (let ((first (car list))) 
    (labels ((helper (list acc) 
       (cond ((null list) acc) 
        ((> (car list) first) 
         (helper (cdr list) (1+ acc))) 
        (t (helper (cdr list) acc))))) 
     (helper (cdr list) 0)))) 

そしてもちろん再帰の

がスタックを吹く可能性があります:あなたが今より多くの引数を追加する可能性を持っているので、私は、アキュムレータを追加しています

(defun count-larger-than-first (list) 
    (let ((first (car list))) 
    (loop :for element :in (cdr list) 
      :counting (> element first)))) 

より適切であるかもしれない、あまりにもカウント高階関数があります。

(defun count-larger-than-first (list) 
    (let ((first (car list))) 
    (count-if (lambda (element) (> element first)) 
       (cdr list)))) 
+0

本当に助けてくれてありがとう。私はそれをテストし、それは完璧に動作します!また、初めにあなたの役に立つアドバイスをありがとう、私はkとラベルの使用と私の間違いについてすべてを理解した:)! – SomethingGeneral

5

はのは、あなたの問題を離れてみましょう。

あなたは数字のセットを持っています。本当に、あなたは「特別な」最初の数、および、それらの残りの部分を持っています。 「未満」は、複雑な(架空の)数字の面で意味がありませんので、具体的には、あなたはおそらく、実数のみをしたいです。

firstを使用すると、リストの最初の番号を取得し、その他の番号はrestにすることができます。

これらのうち、最初のものよりも大きくないものを数えたいとします。そう、

それでは、擬似コード

(defun count-numbers-greater-than-first (list) 
    ;; split out first and rest 
    ;; call the real count function 
) 

まあ、一種の始めましょう、我々が使用できることを今知っているfirstrest(も、あなたが歴史的にcarcdr、使用されるような):

(defun count-numbers-greater-than-first (list) 
    (count-numbers-greater-than (first list) (rest list)) 

>は、実数が互いに重複しているかどうかをテストするために使用されていることは既にご存知でしょう。

CLHSで簡単に見はfunction型のオブジェクト、または関数の名前であることをcount-if

(defun count-numbers-not-greater-than (reference other-numbers) 
    (count-if ??? other-numbers)) 

???ニーズと呼ばれる素敵な機能を明らかにする。その機能にreference(最初の番号)を「カレーする」必要があります。これは、すでにcount-ifを実行していて、すでにreferenceの値を「クローズ」している新しい関数を作成することを意味します。我々はnumberは常に100、たとえば、あろうことを知っていた場合

、その関数は次のようになります。

(defun greater-than-100 (number) 
    (> number 100)) 

その関数は、count-ifに慣れることができます:

(defun count-numbers-greater-than (reference other-numbers) 
    (count-if (function greater-than-100) 
       other-numbers)) 

(defun count-numbers-greater-than (reference other-numbers) 
    (count-if #'greater-than-100 other-numbers)) 

しかし、この関数に数字が「カリングされた」という問題を解決しません。

アレクサンドリアに到達せずに(私は瞬時に説明します)、lambdaフォームを使用してここに新しい無名関数を作成できます。 referencecount-numbers-not-greater-thanにありますので、その値はlambda以内で使用できます。のは、100最初のために変換してみましょう:

(defun count-numbers-greater-than (reference other-numbers) 
    (count-if (lambda (number) (> number 100)) 
       other-numbers)) 

今、私たちはreferenceを使用することができます。

(defun count-numbers-greater-than (reference other-numbers) 
    (count-if (lambda (number) (> number reference)) 
       other-numbers)) 

そして、あなたが望んでいた場合、実際に、あなたも、他の機能にこれをバックマージすることができます:

(defun count-numbers-greater-than-first (list) 
    (count-if (lambda (number) (> number (first list))) 
       (rest list))) 

アレキサンドリアのもの

しかし、アレクサンドリアはどうですか? Alexandriaは、Quicklispや他の場所で利用可能な超便利なユーティリティ関数のコレクションです。もちろん

(ql:quickload "alexandria") 

(use-package #:alexandria) 

、あなたは通常use、それが提供するものの独自のdefpackage

(defpackage my-cool-program 
    (:use :common-lisp :alexandria)) 

二つにcurryrcurry機能していると思います。それは、実際には共通のケースがあることになることが判明した、lambda機能。既存の関数(ここでは>)は、同じ値を何度も繰り返して呼び出す必要があります。また、毎回渡す必要がある未知の値もあります。

これらは、このように多くのことを見て終わる:

(lambda (x) (foo known x)) 

あなたはより簡潔に同じことを書くためにcurryを使用することができます。

(curry #'foo known) 

また、任意の数の引数で動作します。 RCurryは同じことをしますが、未知の値「x」を左側に、既知の値を右側に置きます。

(lambda (x) (foo x known)) = (rcurry #'foo known) 

のでcount-ifを書くための別の方法は次のとおりです。

(defun count-numbers-greater-than-first (list) 
    (count-if (rcurry #'> (first list)) 
       (rest list))) 

* (count-numbers-greater-than-first '(10 9 8 7 11 12)) 

2 
+0

うわー、良い解説をありがとう、すべてのソリューションは完璧に動作し、完全に理解できました! – SomethingGeneral

関連する問題