Schon ein wenig her, aber ich versuche mich mal dran:

(for-each (i (list 1 2 3)) (write i) (terpri))

ist meine Eingabe, die das Macro übersetzen soll - das terpri dient nur dem Zeilenvorschub nach der Ausgabe. Ich habe mich mal dazu entschlossen, keine vorhandenen Schleifen-Befehle zu verwenden, sondern mit Rekursion zu arbeiten.

Das heißt, aus dem obigen soll etwas werden, das in etwa so aussieht:

(labels ((func-name (l)
            (when l
               (let ((i (car l)))
                   (write i)
                   (terpri))
               (func-name (cdr l)))))
   (func-name lst))

Da wird also die Funktion func-name mit der Liste aufgerufen. Solange die Liste nicht leer ist, wird das erste Element der Liste der Variablen i zugewiesen und die Befehle abgearbeitet. Anschließend ruft sich die Funktion rekursiv mit dem Rest der Liste (ohne das erste Element) auf, bis die Liste leer ist.

Ein Macro, dass dies bewerkstelligt könnte beispielsweise so aussehen:

(defmacro for-each(box &rest body)
  (destructuring-bind (var lst) box
    (let ((func-name (gensym)))
      `(labels ((,func-name (l)
		  (when l
		    (let ((,var (car l)))
		      ,@body)
		    (,func-name (cdr l)))))
	 (,func-name ,lst)))))

Wendet man den Befehl macroexpand auf dieses Beispiel an, dann erhält man:

(macroexpand '(for-each (i (list 1 2 3)) (write i) (terpri)))
(LABELS ((#:G557 (L)
           (WHEN L
             (LET ((I (CAR L)))
               (WRITE I)
               (TERPRI))
             (#:G557 (CDR L)))))
  (#:G557 (LIST 1 2 3)))

Schön zu sehen ist hier, wie der Name der Funktion durch das gensym automatisch gewählt wird.

Was du allerdings mit dem translate meinst, habe ich nicht ganz begriffen. Vielleicht kannst du das nochmal genauer erläutern?

Vlati

...zur Antwort

Hallo Luca,

ist zwar schon etwas älter, aber vielleicht hat ja noch jemand Probleme damit. Tatsächlich ist deine Lösung absolut richtig. Weshalb dein ghci sie nicht akzeptiert ist unklar:

Prelude> let  splitStr n a = (take n a, drop n a)

Prelude> print (splitStr 5 "WurstBrot")
("Wurst","Brot")

Vlati

...zur Antwort

Dazu müsste man wissen, was passieren soll, wenn die eine Liste zu Ende ist? Du könntest auch eine rekursive Funktion bauen:

bla (a:as) (b:bs) = (a:b:(bla as bs))
bla [] b = b
bla a [] = a
bla [] [] = []

Solange also a und b noch nicht zu Ende sind, nimmt er ein a und ein b und hängt dann den Rest rekursiv dran. Ist a oder b zu Ende, hängt er b oder a komplett dran. Sind beide zu Ende, wird nichts angehängt.

Vlati

...zur Antwort