2012-04-02 8 views

Antwort

11

Ja, es gibt eine obere Grenze, aber die genaue obere Grenze ist implementierungsabhängig. Du kannst garantiert mindestens 50 Punkte passieren, aber alles hängt davon ab. Wenn Sie eine Liste zusammenfassen müssen, sind Sie wahrscheinlich besser dran mit (reduce #'+ list), die Ihnen eine viel bessere Skalierbarkeit als jede andere Methode bieten sollte.

Common Lisp HyperSpec hat weitere Informationen.

Wenn es um Wertebereiche geht, gibt es zwei verschiedene Fälle, Floats und Integers. Floats sind von Natur aus durch ihre Größe begrenzt und eine Implementierung, die sich von Single-Floats zu Double-Floats geändert hat, würde mich sehr überraschen. Mit Ganzzahlen und Rationalen wechselt CL nahtlos zwischen Fixnum und Bignum, sodass das Limit eine Funktion des nutzbaren Adressraums ist, der für die Implementierung verfügbar ist. Ich vermute, das gleiche gilt für komplexe Zahlen (komplexe Zahlen und rationale Zahlen -> gehe bei Bedarf zu bignums; komplexe Schwebewerte -> signalisiere einen außerhalb des Bereichs liegenden Wert oder gebe ein Inf oder NaN zurück).

+0

Das ist, was die Spezifikation sagt, aber wissen Sie von Implementierungen, die tatsächlich ein Limit erzwingen? – Marcin

+2

@Marcin Nun, SBCL garantiert Ihnen eine CALL-ARGUMENTS-LIMIT in der Region von 10^18 und ich würde erwarten, dass mehr Argumente übergeben, dass das einfach nicht funktionieren würde. Ich habe keine anderen Implementierungen trivial zur Hand, aber ich erinnere mich daran, über Leute gelesen zu haben, die Probleme mit APPLY anstelle von REDUCE mit so kurzen Listen wie "in Hunderten von Elementen" haben. – Vatine

+1

@Vatine Ich habe gerade festgestellt, dass mein Titel und meine Fragebeschreibung sich in ihrer beabsichtigten Bedeutung widersprechen. Da ich denke, dass Sie das Wertlimit der Funktion "+" beantworten, können Sie das Limit von _inputs, das die Funktion haben kann, kommentieren? Entschuldigung für die Verwirrung! – Soyuz

-1

Einfache Antwort, nein, obwohl eine schlechte Implementierung Rekursion und nicht Endrekursion einen Stapel Grenze haben wird.

Abhängig von Ihrer Implementierung + kann durch Rekursion oder als direkter Funktionsaufruf implementiert werden.

Ich kenne Common Lisp nicht gut genug, um zu wissen, welche Anforderungen es angibt, aber die meisten Implementierungen, wenn sie Rekursion verwenden, werden Tail-Rekursion verwenden und irgendwelche Stack-Limits vermeiden.

Ein Funktionsaufruf kann auf die Argumente als Liste zugreifen, so dass die Anzahl der Argumente, die verarbeitet werden können, unbegrenzt ist.

EDIT: Da jemand tatsächlich eine Common Lisp-Referenz gegeben hat, sollte es eindeutig eine bessere Antwort sein, aber ich hätte gedacht, dass jede gute Implementierung das Äquivalent von (reduce #'+ arg-list) automatisch anwenden würde, wenn genug Argumente geliefert werden.

+0

Gemeinsame Lisps sind im Allgemeinen nicht tail rekursiv. Ich habe das Gefühl, dass ich gelesen habe, dass es einen Grund gibt, warum sie keine Tail-Call-Optimierung haben dürfen (obwohl ich mir das vielleicht einbilde). – Marcin

+1

Es gibt auch keinen Grund, warum eine Implementierung Rekursion verwenden würde, da "reduce" und "loop" zur Verfügung stehen. – Marcin

+2

@Marcin Sie dürfen Tail-Call-Optimierung haben und die meisten tun, wenn Sie Ihre Optimierungsvariablen (in erster Linie "Geschwindigkeit" hoch und "Debug" niedrig, aber sehen Sie das Handbuch der Implementierung für Besonderheiten). – Vatine

8

Common Lisp wurde so definiert, dass es effizient auf einer Vielzahl von Hardware- und Softwaresystemen implementiert werden kann. Beispiele sind Prozessoren wie das Motorola 68000/20/30/40, die verschiedenen Intel x86-Prozessoren, Stack-basierte Prozessoren von Lisp Machine, DEC VAX, RISC-Prozessoren, Supercomputer wie die von Cray. In den 80er Jahren konkurrierten viele Prozessorfamilien miteinander, darunter Prozessoren, die für die Ausführung von Lisp-Code entwickelt wurden. Heute haben wir noch mehrere Prozessorfamilien (x86, x86-64, ARM, SPARC, POWER, PowerPC, ...).

Es kann auch nach C, Scheme oder anderen Programmiersprachen kompiliert werden.

Es kann auch in virtuelle Maschinen wie die von CMUCL, CLISP oder der JVM/Java Virtual Machine kompiliert werden (Die Java Virtual Machine scheint ein Limit von 254 Argumenten zu haben).

Zum Beispiel könnte ein Common Lisp-Compiler Lisp-Code zu geradlinigem C-Code kompilieren. Daher wäre es gut, wenn so viel von dem Funktionsaufruf des C-Compilers wie möglich wiederverwendet werden könnte. Vor allem auch, um Lisp von C einfacher zu machen.

C/C++ hat Grenzen auf, dass auch:

Maximum number of parameters in function declaration

Above gibt Zahlen wie 127 (C) und 256 für C++. Für einen Lisp-zu-C-Compiler könnten das die Grenzen sein. Andernfalls würde der Lisp-Code nicht die C-Funktion aufrufen.

Die erste Compiler KCL (Kyoto Common Lisp, später diese Implementierung in GCL/GNU Common Lisp und ECL/Fähiges Common Lisp entwickelt) hatte eine CALL-ARGUMENTS-LIMIT von 64

Eine 64-Bit-Implementierung von LispWorks/Mac OS X hat zum Beispiel einen Wert von 2047 für CALL-ARGUMENTS-LIMIT.

CALL-ARGUMENTS-LIMIT sollte nicht kleiner als 50

So in Common Lisp, Listenverarbeitung und Aufruf Argumente sind nicht verwandt. Wenn Sie Listen bearbeiten wollen, müssen Sie die Werkzeuge zur Listenbearbeitung (LIST, MAPCAR, APPEND, REDUCE, ...) verwenden. Common Lisp bietet einen Mechanismus zum Zugriff auf die Argumente als Liste mit einem &REST Parameter. Dies sollte jedoch in der Regel vermieden werden, da dies zu Funktionsaufrufen führen kann, da eine Liste der Argumente konfligiert werden muss.

2

Clojure ist ein Beispiel für eine Lisp, wo man tatsächlich eine unendliche Anzahl von Argumenten an eine Funktion, über die Verwendung von faulen Sequenzen hat:

; infinite lazy sequence of natural numbers 
(def naturals (iterate inc 1)) 

(take 10 naturals) 
=> (1 2 3 4 5 6 7 8 9 10) 

; add up all the natural numbers 
(apply + naturals) 
=> ...... [doesn't terminate] 

nicht besonders nützlich, natürlich .....

+0

Dieses Beispiel überzeugt mich nicht. APPLY wird mit zwei Argumenten aufgerufen. Dass + mit unendlichen Argumenten aufgerufen wird, ist nicht klar. Vielleicht ist APPLY beschäftigt, BEVOR + mit unendlichen Argumenten aufgerufen wird. Angesichts des Beispiels von @jwinandy, dass Clojure bei 8192 Argumenten "hängt", würde ich vermuten, dass dies auch hier passiert ... –

2

Es hängt von der Implementierung ab. "Ich würde vorschlagen, dass LISP-Benutzer 5 Minuten brauchen, um ihre Plattform zu testen".

Für Clojure

(defn find-max-n [n] 
    (try 
    (eval (concat (list +) (take n (repeat 1)))) 
    (println "more than" n) 
    ; return n if something goes wrong 
    (catch Exception e n)) 
    (recur (* n 2))) 


(find-max-n 1) 

Es endet nicht, hängt es bei 8192 meine Einstellungen gegeben.

more than 1 
more than 2 
more than 4 
more than 8 
more than 16 
more than 32 
more than 64 
more than 128 
more than 256 
more than 512 
more than 1024 
more than 2048 
more than 4096 
more than 8192 
Verwandte Themen