# Scheme



## sanni7 (10. Februar 2009)

Hallo zusammen,
ich soll einer Funktion erstellen, die folgendes macht: ((1 2 3) (4 5 6) (7 8 9)) -> ((1 4 7) (2 5 8 ) (3 6 9)) also jeweils die ersten der einzelnen Listen zu einer neuen Liste, die zweiten etc. Wie ich an die ersten komme und daraus eine Liste hinbekomme habe ich so gemacht:

(define firsts
(lambda (l)
(cond
((empty? l) '())
(else (cons (car (car l)) (firsts (cdr l)))))))

Aber wie rufe ich das nun nochmal auf, quasi ohne die ersten der Liste, um dann wiederum die neuen ersten (also die jetzigen 2ten) aneinanderzufügen? Und vor allem wie merke ich mir die Liste?

Wäre super, wenn mir jemand helfen kann


----------



## deepthroat (10. Februar 2009)

Hi.

Welche Funktionen kennst du denn schon?

Du müßtest im Grunde zu der Liste die du mit firsts bekommst nur noch die Liste dranhängen die du bekommst indem du aus allen Listen das erste Element entfernst und darauf noch mal die eigentliche Funktion anwendest:


```
func X => [ firsts(X) ] + func(reste(X))
```
Gruß

PS: Es gibt auch noch eine sehr elegante Möglichkeit dies in Scheme zu tun. Verrate ich dir aber erst später...


----------



## sanni7 (10. Februar 2009)

Leider ist mir keine Funktion bekannt um elegant die ersten verschwinden zu lassen.

Dieses hier ist meine Version, die ersten zu entfernen:
(define remove-firsts
  (lambda (l)
    (cond
      ((empty? l) '())
      (else (cons(cdr (car l)) (remove-firsts (cdr l)))))))


----------



## deepthroat (10. Februar 2009)

sanni7 hat gesagt.:


> Leider ist mir keine Funktion bekannt um elegant die ersten verschwinden zu lassen.
> wenn ich nur eine liste hätte würde ich ja einfach mit dem cdr l weiterarbeiten, aber die kann ich ja leider nicht aneinander "consen"


Du solltest dir erstmal eine Funktion wie firsts schreiben welche nur die Reste, also die cdr, der Unterlisten der Gesamtliste zurückgibt:

```
reste X = cons(cdar(X), reste(X))
```
Gruß


----------



## sanni7 (10. Februar 2009)

gerade geschehen  siehe oben


----------



## deepthroat (10. Februar 2009)

sanni7 hat gesagt.:


> gerade geschehen  siehe oben


Gut. Jetzt kannst du damit deine eigentliche Funktion erstellen. Dazu mußt du nur zu den ersten Elementen die du mit firsts bekommst das Ergebnis der Funktion anhängen die du mit den Rest-Elementen als Parameter aufrufst. (siehe Pseudo-Code oben)

Gruß


----------



## sanni7 (10. Februar 2009)

irgendwie fehlt mir der letzte schritt zur rekursivität

(define umformung
  (lambda (l)
       (cond
         ((empty? l) '())
           (else
            (cons (firsts l)(cons(firsts (remove-firsts l))'())))
             ) 
           )
    )

so habe ich jetzt die ersten und die zweiten aneinander, aber irgendwie funktionieren meine ganzen versuche, das ganze rekursiv zu machen nicht...

Bsp.
(umformung '((1 2 3) (4 5 6) (7 8 9)) --> ((1 4 7) (2 5 8)), aber ich möchte (3 6 8) ja auch noch enthalten haben, bzw. beliebig viele, wenn die liste 4 listen enthält soll er natürlich alleine auch die vierten ranhängen


----------



## deepthroat (10. Februar 2009)

Hi.

Bitte halte dich an die Netiquette, insbesondere Punkt 15, Groß-/Kleinschreibung. Danke!


sanni7 hat gesagt.:


> irgendwie fehlt mir der letzte schritt zur rekursivität


Ja, dann ruf doch die Funktion rekursiv auf! Warum wendest du denn die firsts Funktion 2 Mal an? Schau dir nochmal den Pseudocode von mir an.

Und bitte verwende für Code die Code Tags!

Gruß


----------



## sanni7 (10. Februar 2009)

Entschuldige, war keine Absicht. Danke für den Hinweis.
Ich weiß theoretisch, dass ich das mit einer Rekursion machen muss, leider weiß ich nicht, wie man das praktisch macht


```
(define transpose
  (lambda (l)
       (cond
         ((empty? l) '())
           (else
            (cons (firsts l)(transpose (remove-firsts l)))))
             ) 
           )
```

Das war mein Versuch deinen Pseudocode umzusetzen, aber dann bekomme ich die Fehlermeldung, dass () gegeben ist, er aber ein Argument vom Typ pair erwartet


----------



## deepthroat (10. Februar 2009)

sanni7 hat gesagt.:


> Entschuldige, war keine Absicht. Danke für den Hinweis.
> Ich weiß theoretisch, dass ich das mit einer Rekursion machen muss, leider weiß ich nicht, wie man das praktisch macht
> 
> 
> ...


OK. Das liegt noch an der remove-firsts Funktion, da diese für den Parameter ((3) (6) (9)) den Wert (() () ()) zurückliefert. Ein weiterer Aufruf der Funktion schlägt dann natürlich fehl, da du keine Elemente mehr aus den leeren Unterlisten entfernen kannst. Du müßtest also prüfen, ob auch die Unterliste nicht leer ist.

Gruß


----------



## sanni7 (10. Februar 2009)

Ich glaube ich habs jetzt:


```
(define transpose
  (lambda (l)
       (cond
         ((empty? l) '())
           (else
            (cond
              ((empty? (car l)) '())
           (else
              (cons (firsts l)(transpose (remove-firsts l)))))
             ) 
           )
    )
  )
```

Vielen Dank für deine  Hilfe!


----------



## deepthroat (10. Februar 2009)

sanni7 hat gesagt.:


> Ich glaube ich habs jetzt:
> 
> 
> ```
> ...


Ja, so herum ist es sogar besser, da nun folgendes relativ auffällig ist:

Im Grunde hast du - bis auf eine Kleinigkeit - 2 Mal die gleiche Funktion definiert. Einmal firsts und dann remove-firsts. Diese Funktionen haben im Grunde die gleiche Struktur. Und zwar wird in beiden auf jedem Element einer Liste eine Funktion ausgeführt und das Ergebnis ist eine Liste die aus den Ergebnissen gebildet wird.

Da kann man sich gleich eine allgemeine Funktion bauen:

```
(define (funktion-auf  func  liste)
  (cond ((empty? liste) liste)
       (else (cons (func (car liste)) (funktion-auf func (cdr liste))))))

;; Funktion firsts:

(define (firsts x)
  (funktion-auf ?   x))

;; Funktion remove-firsts:

(define (remove-firsts x) 
  (funktion-auf  ? x))
```
Kannst ja mal überlegen was in die Fragezeichen eingesetzt werden muss. 

Gruß


----------



## sanni7 (10. Februar 2009)

Stimmt, die sind ja echt total gleich. Man bin ich blind  Danke für den Hinweis.
Meine Fassung sieht jetzt so aus:


```
(define hilfs-func
  (lambda (func l)
    (cond
      ((empty? l) '())
      (else
       (cons (func(car l))(hilfs-func func(cdr l)))))))


(define (firsts l)
  (hilfs-func car l))

(define (remove-firsts l)
  (hilfs-func cdr l))


(firsts '((1 2 3)(4 5 6) (7 8 9)))
(remove-firsts '((1 2 3) (4 5 6)))
     

(define transpose
  (lambda (l)
       (cond
         ((empty? l) '())
           (else
            (cond
              ((empty? (car l)) '())
           (else
              (cons (firsts l)(transpose (remove-firsts l)))))
             ) 
           )
    )
  )
```


----------



## deepthroat (10. Februar 2009)

Ja, sieht gut aus. Aber natürlich gibt es bereits eine Funktion die eine Funktion auf jedes Element einer Liste anwendet und eine Liste der Resultate zurückgbit, sie heißt *map*. 

Wie angesprochen gibt es noch eine sehr elegante Möglichkeit eine Liste von Listen zu transponieren in Scheme, aber dazu braucht man noch eine andere Funktion; und das führt jetzt womöglich zu weit...

Gruß


----------



## sanni7 (10. Februar 2009)

Ein anderes Mal gerne für heute reicht es erst einmal 

Gruß


----------



## deepthroat (12. Februar 2009)

Hi.

Irgendwie muss ich es jetzt doch loswerden, außerdem wollte ich schon immer mal einen Spoiler verwenden 


Spoiler





```
(define (transpose a-list)
  (apply map list a-list))
```



Gruß


----------

