Bridge-Methode für Pattern Matching in Funktionsköpfen #355

Open
opened 2024-12-06 10:28:28 +00:00 by dholle · 9 comments
Owner

Das Pattern-Matching in Funktionsköpfen soll das unter Java verwendete Visitor-Pattern ersetzen.
Hierzu folgendes Beispiel:

sealed interface List<T> permits Cons, Empty {}

public record Cons<T>(T a, List<T> l) implements List<T> {}
public record Empty<T>() implements List<T> {}

public class PatternMatchingListAppend {

    public append(Cons(a, b), list2) {
        return new Cons<>(a, append(b, list2));
    }

    public append(Empty(), list2) {
        return list2;
    }
}

Bislang werden nur Überladungen für die einzelnen Funktionen erstellt. Da Java aber kein multiple dispatch auf Funktionsargumente implementiert ist dies hier nicht zielführend.
Java braucht eine Bridge-Methode welche als erstes Argument List übergeben bekommt. Diese muss vom Compiler generiert werden.
Da hier konkrete Typen verwendet werden (Cons & Empty) taucht der Typ List im Result-Set allerdings nicht auf.

Um das Ganze umzusetzen muss für das erste Argument zunächst ein Supertyp gefunden werden. Die Methoden mit der selben Signatur (append) werden hier zusammengefasst. Der Supertyp muss ein sealed Interface sein und alle Fälle (siehe permits-Klausel) müssen abgedeckt werden. Nur wenn dies der Fall ist kann eine Bridge-Methode erstellt werden.

Die Bridge-Methode besteht dann aus einem switch-Statement welches zur Laufzeit die Typen überprüft und die richtige Implementierung aufruft.

Ein mögliches Problem bei der Umsetzung könnte sein, dass die Typinferenz nichts von der Bridge-Methode weiß und diese deshalb nicht aufrufen kann.

Das Pattern-Matching in Funktionsköpfen soll das unter Java verwendete Visitor-Pattern ersetzen. Hierzu folgendes Beispiel: ```java sealed interface List<T> permits Cons, Empty {} public record Cons<T>(T a, List<T> l) implements List<T> {} public record Empty<T>() implements List<T> {} public class PatternMatchingListAppend { public append(Cons(a, b), list2) { return new Cons<>(a, append(b, list2)); } public append(Empty(), list2) { return list2; } } ``` Bislang werden nur Überladungen für die einzelnen Funktionen erstellt. Da Java aber kein multiple dispatch auf Funktionsargumente implementiert ist dies hier nicht zielführend. Java braucht eine Bridge-Methode welche als erstes Argument `List` übergeben bekommt. Diese muss vom Compiler generiert werden. Da hier konkrete Typen verwendet werden (`Cons` & `Empty`) taucht der Typ `List` im Result-Set allerdings nicht auf. Um das Ganze umzusetzen muss für das erste Argument zunächst ein Supertyp gefunden werden. Die Methoden mit der selben Signatur (`append`) werden hier zusammengefasst. Der Supertyp muss ein sealed Interface sein und alle Fälle (siehe permits-Klausel) müssen abgedeckt werden. Nur wenn dies der Fall ist kann eine Bridge-Methode erstellt werden. Die Bridge-Methode besteht dann aus einem switch-Statement welches zur Laufzeit die Typen überprüft und die richtige Implementierung aufruft. Ein mögliches Problem bei der Umsetzung könnte sein, dass die Typinferenz nichts von der Bridge-Methode weiß und diese deshalb nicht aufrufen kann.
dholle added the
Codegen
label 2024-12-06 10:28:28 +00:00
dholle self-assigned this 2024-12-06 10:28:28 +00:00
pl was assigned by dholle 2024-12-06 10:28:28 +00:00
Author
Owner

Ich habe mich jetzt mal dran gesetzt und ein weiteres Problem gefunden.
Hier werden von der Typinferenz 6 Methoden generiert:

append(Cons, Object)
append(Cons, Empty)
append(Cons, Cons)
append(Empty, Object)
append(Empty, Empty)
append(Empty, Cons)

Wenn ich jeweils nach einem Super-Interface suche sieht die Gruppierung so aus:

1:
    append(Cons, Object)

2:
    append(Cons, Empty)
    append(Cons, Cons)
    append(Empty, Empty)
    append(Empty, Cons)
3:
    append(Empty, Object)

Für das richtige Ergebnis müssten allerdings alle diese Methoden in die selbe Gruppe kommen.
Object entspricht ja beim zweiten Parameter dem "default"-Fall. Ich weiß allerdings nicht wie ich das erkennen soll.
@pl Hast du da eine Idee?

Ich habe mich jetzt mal dran gesetzt und ein weiteres Problem gefunden. Hier werden von der Typinferenz 6 Methoden generiert: ``` append(Cons, Object) append(Cons, Empty) append(Cons, Cons) append(Empty, Object) append(Empty, Empty) append(Empty, Cons) ``` Wenn ich jeweils nach einem Super-Interface suche sieht die Gruppierung so aus: ``` 1: append(Cons, Object) 2: append(Cons, Empty) append(Cons, Cons) append(Empty, Empty) append(Empty, Cons) 3: append(Empty, Object) ``` Für das richtige Ergebnis müssten allerdings alle diese Methoden in die selbe Gruppe kommen. Object entspricht ja beim zweiten Parameter dem "default"-Fall. Ich weiß allerdings nicht wie ich das erkennen soll. @pl Hast du da eine Idee?
Author
Owner

Die Gruppierung war falsch, Object & Object sind logischerweise auch gleich (In diesem Fall hat es nicht geklappt weil beides Generics waren).

1:
    append(Cons, Object)
    append(Empty, Object)
2:
    append(Cons, Empty)
    append(Cons, Cons)
    append(Empty, Empty)
    append(Empty, Cons)

Jetzt gibt es allerdings wieder das gleiche Problem.
Meiner Meinung nach braucht man hier auch nur die Gruppe 1, Gruppe 2 ist komplett unnötig.

Hier würden dann zwei Bridge-Methoden generiert werden:

Object append(List __par0, Object list2)
Object append(List __par0, List list2) // Braucht man im Prinzip nicht

Das könnte vielleicht funktionieren. Generics fallen leider komplett raus, keine Ahnung wie ich die generieren soll.

Die Gruppierung war falsch, Object & Object sind logischerweise auch gleich (In diesem Fall hat es nicht geklappt weil beides Generics waren). ``` 1: append(Cons, Object) append(Empty, Object) 2: append(Cons, Empty) append(Cons, Cons) append(Empty, Empty) append(Empty, Cons) ``` Jetzt gibt es allerdings wieder das gleiche Problem. Meiner Meinung nach braucht man hier auch nur die Gruppe 1, Gruppe 2 ist komplett unnötig. Hier würden dann zwei Bridge-Methoden generiert werden: ``` Object append(List __par0, Object list2) Object append(List __par0, List list2) // Braucht man im Prinzip nicht ``` Das könnte vielleicht funktionieren. Generics fallen leider komplett raus, keine Ahnung wie ich die generieren soll.
Owner

Ich schlage folgende Änderungen vor

public append(Cons(a, b), list2) {
return new Cons<>(a, append(b, list2));
}

In AbsSyn:
TPH AQ append(Cons(TPH AR a, TPH AS b), TPH AU list2)({
return new Cons((a)::TPH AR, ((this)::TPH AW.append Signature: [TPH AX, TPH AY, TPH AZ]((b)::TPH AS, (list2)::TPH AU))::TPH BA);
})::TPH BF

AR und AS müssen Typen bekommen:
AR = AT (folgt aus der Def von Cons)
AS = List (folgt aus der Def von Cons)

append in den Assumptions jetzt den Typ (Cons, AU) -> AQ
sollte den Typ (AFresh, AU) -> AQ bekommen
Zusätzlich werden die Constraints
AFresh <. List (List kommt aus der implements Deklaration im Record) und
Cons <. AFresh
hinzugefügt

Ich schlage folgende Änderungen vor public append(Cons(a, b), list2) { return new Cons<>(a, append(b, list2)); } In AbsSyn: TPH AQ append(Cons<TPH AT>(TPH AR a, TPH AS b), TPH AU list2)({ return new Cons((a)::TPH AR, ((this)::TPH AW.append Signature: [TPH AX, TPH AY, TPH AZ]((b)::TPH AS, (list2)::TPH AU))::TPH BA); })::TPH BF _AR und AS müssen Typen bekommen: AR = AT (folgt aus der Def von Cons) AS = List<AT> (folgt aus der Def von Cons)_ append in den Assumptions jetzt den Typ (Cons<TPH AT>, AU) -> AQ _sollte den Typ (AFresh, AU) -> AQ bekommen Zusätzlich werden die Constraints AFresh <. List<AT> (List <AT> kommt aus der implements Deklaration im Record) und Cons<AT> <. AFresh hinzugefügt_
Author
Owner

Ich bekomme jetzt folgendes Ergebnis:

// append(Cons(a, b), list2)
public <AEM extends AEI, AEI> Cons<AEI> append(Cons<AEM> var1, Cons<AEI> var2)

public <AEI, AEG extends AEI> Cons<AEI> append(Cons<AEG> var1, Empty<AEI> var2)

public <AEY extends ABT, AV, ABT> Cons<ABT> append(List<AEY> var1, AV var2)

// append(Empty(), list2)
public <BK, AEW> BK append(Empty<AEW> var1, BK var2)

public <AEM extends AEI, AEI> Cons<AEI> append(List<AEM> var1, Cons<AEI> var2)

public <AEI, AEG extends AEI> Empty<AEI> append(List<AEG> var1, Empty<AEI> var2)

Sieht das richtig aus?
Die Constraints sind hier:

UND:[(T <. T, )@6 in PatternMatchingListAppend.jav, (AS =. List<ABS>, 0 WC: true, IT: false), (Cons<AW> <. AQ, , -1 WC: false, IT: false)@12 in PatternMatchingListAppend.jav, (Empty<BI> <. BJ, , 0 WC: true, IT: false), (java.lang.Record =. java.lang.Record, ), (List<T> <. List<T>, )@6 in PatternMatchingListAppend.jav, (BJ <. List<ABU>, 0 WC: true, IT: false), (AA =. Cons<T>, 0 WC: true, IT: false)@6 in PatternMatchingListAppend.jav, (java.lang.Object =. java.lang.Object, ), (AC =. Cons<T>, 0 WC: true, IT: false)@6 in PatternMatchingListAppend.jav, (AU <. List<ABS>, 0 WC: true, IT: false), (BK <. BH, 1 WC: false, IT: false, -1 WC: false, IT: false)@16 in PatternMatchingListAppend.jav, (AR =. ABS, 0 WC: true, IT: true, 0 WC: true, IT: true), (Cons<AT> <. AU, , 0 WC: true, IT: false), (AX =. PatternMatchingListAppend, 0 WC: true, IT: false)@12 in PatternMatchingListAppend.jav, (Cons<AT> =. Cons<ABS>, ), (AT =. ABS, 0 WC: true, IT: true, 0 WC: true, IT: true)]

AST:

  TPH AQ append(TPH AU(TPH AR a, TPH AS b), TPH AV list2)({
    return new Cons((a)::TPH AR, ((this)::TPH AX.append Signature: [TPH AY, TPH AZ, TPH BA]((b)::TPH AS, (list2)::TPH AV))::TPH BB);
  })::TPH BG

  TPH BH append(TPH BJ(), TPH BK list2)({
    return (list2)::TPH BK;
  })::TPH BL

Result:

RESULT Final: [
[(TPH BK = Cons<TPH AEI>), (TPH AQ = Cons<TPH AEI>), (TPH AY = List<TPH AEM>), (TPH AEU, TPH AEM), (TPH ABO = GTV T), (TPH BD = GTV T), (TPH ABT, TPH AEI), (TPH AU = Cons<TPH AEM>), (TPH BF = Cons<GTV T>), (TPH AZ = Cons<TPH AEI>), (TPH AX = PatternMatchingListAppend), (TPH AEP = GTV T), (TPH AR, TPH AEM), (TPH BH = Cons<TPH AEI>), (TPH AEO, TPH AEI), (TPH AS = List<TPH AEM>), (TPH ABS, TPH AEM), (TPH AA = Cons<GTV T>), (TPH BB = Cons<TPH AEI>), (TPH AES, TPH AEM), (TPH ABQ = GTV T), (TPH BE = List<GTV T>), (TPH AER, TPH AEI), (TPH AEL, TPH AEM), (TPH BA = Cons<TPH AEI>), (TPH AC = Cons<GTV T>), (TPH AV = Cons<TPH AEI>), (TPH AEN = GTV T), (TPH BJ = List<TPH AEM>), (TPH AT, TPH AEM), (TPH AEM < TPH AEI)],
[(TPH BK = Empty<TPH AEI>), (TPH ABQ = GTV T), (TPH AS = List<TPH AEG>), (TPH BH = Empty<TPH AEI>), (TPH AEJ = GTV T), (TPH ABT, TPH AEI), (TPH AA = Cons<GTV T>), (TPH BE = List<GTV T>), (TPH ABS, TPH AEG), (TPH BA = Empty<TPH AEI>), (TPH AU = Cons<TPH AEG>), (TPH AEG < TPH AEI), (TPH ABO = GTV T), (TPH AX = PatternMatchingListAppend), (TPH AET, TPH AEI), (TPH AC = Cons<GTV T>), (TPH BD = GTV T), (TPH AR, TPH AEG), (TPH AEL = GTV T), (TPH BJ = List<TPH AEG>), (TPH BB = Empty<TPH AEI>), (TPH AZ = Empty<TPH AEI>), (TPH AV = Empty<TPH AEI>), (TPH BF = Cons<GTV T>), (TPH AEH, TPH AEG), (TPH AT, TPH AEG), (TPH AQ = Cons<TPH AEI>), (TPH AEK, TPH AEI), (TPH AEF, TPH AEG), (TPH AY = List<TPH AEG>), (TPH AEQ, TPH AEG)], 
[(TPH BJ = Empty<TPH AEW>), (TPH AEY < TPH ABT), (TPH ABO = GTV T), (TPH AFC, TPH AEW), (TPH BB = Cons<TPH ABT>), (TPH AA = Cons<GTV T>), (TPH AS = List<TPH AEY>), (TPH AFA, TPH ABT), (TPH BD = GTV T), (TPH BF = Cons<GTV T>), (TPH ABS, TPH AEY), (TPH AU = List<TPH AEY>), (TPH AR, TPH AEY), (TPH AQ = Cons<TPH ABT>), (TPH AC = Cons<GTV T>), (TPH BK < TPH BH), (TPH AEV, TPH AEW), (TPH AFB, TPH ABT), (TPH AY = List<TPH AEY>), (TPH ABQ = GTV T), (TPH AX = PatternMatchingListAppend), (TPH AEX = GTV T), (TPH AEZ = GTV T), (TPH AT, TPH AEY), (TPH BE = List<GTV T>), (TPH AZ, TPH AV), (TPH BA = Cons<TPH ABT>)]
]

Ich pushe mal, der Bytecode ist sowieso nicht valide weil die Bridge-Methoden fehlen.

Ich bekomme jetzt folgendes Ergebnis: ```java // append(Cons(a, b), list2) public <AEM extends AEI, AEI> Cons<AEI> append(Cons<AEM> var1, Cons<AEI> var2) public <AEI, AEG extends AEI> Cons<AEI> append(Cons<AEG> var1, Empty<AEI> var2) public <AEY extends ABT, AV, ABT> Cons<ABT> append(List<AEY> var1, AV var2) // append(Empty(), list2) public <BK, AEW> BK append(Empty<AEW> var1, BK var2) public <AEM extends AEI, AEI> Cons<AEI> append(List<AEM> var1, Cons<AEI> var2) public <AEI, AEG extends AEI> Empty<AEI> append(List<AEG> var1, Empty<AEI> var2) ``` Sieht das richtig aus? Die Constraints sind hier: ``` UND:[(T <. T, )@6 in PatternMatchingListAppend.jav, (AS =. List<ABS>, 0 WC: true, IT: false), (Cons<AW> <. AQ, , -1 WC: false, IT: false)@12 in PatternMatchingListAppend.jav, (Empty<BI> <. BJ, , 0 WC: true, IT: false), (java.lang.Record =. java.lang.Record, ), (List<T> <. List<T>, )@6 in PatternMatchingListAppend.jav, (BJ <. List<ABU>, 0 WC: true, IT: false), (AA =. Cons<T>, 0 WC: true, IT: false)@6 in PatternMatchingListAppend.jav, (java.lang.Object =. java.lang.Object, ), (AC =. Cons<T>, 0 WC: true, IT: false)@6 in PatternMatchingListAppend.jav, (AU <. List<ABS>, 0 WC: true, IT: false), (BK <. BH, 1 WC: false, IT: false, -1 WC: false, IT: false)@16 in PatternMatchingListAppend.jav, (AR =. ABS, 0 WC: true, IT: true, 0 WC: true, IT: true), (Cons<AT> <. AU, , 0 WC: true, IT: false), (AX =. PatternMatchingListAppend, 0 WC: true, IT: false)@12 in PatternMatchingListAppend.jav, (Cons<AT> =. Cons<ABS>, ), (AT =. ABS, 0 WC: true, IT: true, 0 WC: true, IT: true)] ``` AST: ``` TPH AQ append(TPH AU(TPH AR a, TPH AS b), TPH AV list2)({ return new Cons((a)::TPH AR, ((this)::TPH AX.append Signature: [TPH AY, TPH AZ, TPH BA]((b)::TPH AS, (list2)::TPH AV))::TPH BB); })::TPH BG TPH BH append(TPH BJ(), TPH BK list2)({ return (list2)::TPH BK; })::TPH BL ``` Result: ``` RESULT Final: [ [(TPH BK = Cons<TPH AEI>), (TPH AQ = Cons<TPH AEI>), (TPH AY = List<TPH AEM>), (TPH AEU, TPH AEM), (TPH ABO = GTV T), (TPH BD = GTV T), (TPH ABT, TPH AEI), (TPH AU = Cons<TPH AEM>), (TPH BF = Cons<GTV T>), (TPH AZ = Cons<TPH AEI>), (TPH AX = PatternMatchingListAppend), (TPH AEP = GTV T), (TPH AR, TPH AEM), (TPH BH = Cons<TPH AEI>), (TPH AEO, TPH AEI), (TPH AS = List<TPH AEM>), (TPH ABS, TPH AEM), (TPH AA = Cons<GTV T>), (TPH BB = Cons<TPH AEI>), (TPH AES, TPH AEM), (TPH ABQ = GTV T), (TPH BE = List<GTV T>), (TPH AER, TPH AEI), (TPH AEL, TPH AEM), (TPH BA = Cons<TPH AEI>), (TPH AC = Cons<GTV T>), (TPH AV = Cons<TPH AEI>), (TPH AEN = GTV T), (TPH BJ = List<TPH AEM>), (TPH AT, TPH AEM), (TPH AEM < TPH AEI)], [(TPH BK = Empty<TPH AEI>), (TPH ABQ = GTV T), (TPH AS = List<TPH AEG>), (TPH BH = Empty<TPH AEI>), (TPH AEJ = GTV T), (TPH ABT, TPH AEI), (TPH AA = Cons<GTV T>), (TPH BE = List<GTV T>), (TPH ABS, TPH AEG), (TPH BA = Empty<TPH AEI>), (TPH AU = Cons<TPH AEG>), (TPH AEG < TPH AEI), (TPH ABO = GTV T), (TPH AX = PatternMatchingListAppend), (TPH AET, TPH AEI), (TPH AC = Cons<GTV T>), (TPH BD = GTV T), (TPH AR, TPH AEG), (TPH AEL = GTV T), (TPH BJ = List<TPH AEG>), (TPH BB = Empty<TPH AEI>), (TPH AZ = Empty<TPH AEI>), (TPH AV = Empty<TPH AEI>), (TPH BF = Cons<GTV T>), (TPH AEH, TPH AEG), (TPH AT, TPH AEG), (TPH AQ = Cons<TPH AEI>), (TPH AEK, TPH AEI), (TPH AEF, TPH AEG), (TPH AY = List<TPH AEG>), (TPH AEQ, TPH AEG)], [(TPH BJ = Empty<TPH AEW>), (TPH AEY < TPH ABT), (TPH ABO = GTV T), (TPH AFC, TPH AEW), (TPH BB = Cons<TPH ABT>), (TPH AA = Cons<GTV T>), (TPH AS = List<TPH AEY>), (TPH AFA, TPH ABT), (TPH BD = GTV T), (TPH BF = Cons<GTV T>), (TPH ABS, TPH AEY), (TPH AU = List<TPH AEY>), (TPH AR, TPH AEY), (TPH AQ = Cons<TPH ABT>), (TPH AC = Cons<GTV T>), (TPH BK < TPH BH), (TPH AEV, TPH AEW), (TPH AFB, TPH ABT), (TPH AY = List<TPH AEY>), (TPH ABQ = GTV T), (TPH AX = PatternMatchingListAppend), (TPH AEX = GTV T), (TPH AEZ = GTV T), (TPH AT, TPH AEY), (TPH BE = List<GTV T>), (TPH AZ, TPH AV), (TPH BA = Cons<TPH ABT>)] ] ``` Ich pushe mal, der Bytecode ist sowieso nicht valide weil die Bridge-Methoden fehlen.
Owner

Zile wäre:

public class PatternMatchingListAppend {

    public append(Cons(a, Cons b), Cons list2) {
        return new Cons<>(a, append(b, list2));
    }
    
    public append(Cons(a, Cons b), Empty list2) {
        return new Cons<>(a, append(b, list2));
    }
    
    public append(Cons(a, Empty b), Cons list2) {
        return new Cons<>(a, append(b, list2));
    }
    
    public append(Cons(a, Empty b), Empty list2) {
        return new Cons<>(a, append(b, list2));
    }

    public append(Empty(), Cons list2) {
        return list2;
    }

	public append(Empty(), Empty list2) {
        return list2;
    }
}
Zile wäre: ```java public class PatternMatchingListAppend { public append(Cons(a, Cons b), Cons list2) { return new Cons<>(a, append(b, list2)); } public append(Cons(a, Cons b), Empty list2) { return new Cons<>(a, append(b, list2)); } public append(Cons(a, Empty b), Cons list2) { return new Cons<>(a, append(b, list2)); } public append(Cons(a, Empty b), Empty list2) { return new Cons<>(a, append(b, list2)); } public append(Empty(), Cons list2) { return list2; } public append(Empty(), Empty list2) { return list2; } } ```
Owner

Das Ergebis ist fast richtig:
[(TPH ACG = GTV T), (TPH ACI = GTV T), (TPH AQ = Cons), (TPH BI = Empty), (TPH AU = Empty), (TPH AC = Cons), (TPH AFO, TPH AFJ), (TPH BG = Empty), (TPH BD = List), (TPH AFL, TPH AFI), (TPH ACL, TPH AFI), (TPH AS = ? extends Empty), (TPH AR < TPH AFI), (TPH AR < TPH AFJ), (TPH AT, TPH AFJ), (TPH BC = GTV T), (TPH AFN = GTV T), (TPH BA = Empty), (TPH AFM = GTV T), (TPH AA = Cons), (TPH AZ = Empty), (TPH AY = Empty), (TPH AX = Empty), (TPH AW = PatternMatchingListAppend), (TPH AFK, TPH AFI), (TPH ACK, TPH AFJ), (TPH BE = Cons)],
[(TPH BC = GTV T), (TPH AFQ = GTV T), (TPH AR < TPH AFJ), (TPH AFP, TPH AFH), (TPH BE = Cons), (TPH BA = Cons), (TPH AR < TPH AFH), (TPH AFR = GTV T), (TPH AS = ? extends Empty), (TPH AX = Empty), (TPH AA = Cons), (TPH AY = Cons), (TPH ACG = GTV T), (TPH AFS, TPH AFJ), (TPH AZ = Cons), (TPH AFG, TPH AFH), (TPH ACK, TPH AFJ), (TPH BI = Cons), (TPH AC = Cons), (TPH ACI = GTV T), (TPH BD = List), (TPH AU = Cons), (TPH AT, TPH AFJ), (TPH AQ = Cons), (TPH AW = PatternMatchingListAppend), (TPH ACL, TPH AFH), (TPH BG = Cons)],
[(TPH AFX, TPH AFT), (TPH BC = GTV T), (TPH AC = Cons), (TPH ACI = GTV T), (TPH AFW, TPH ACK), (TPH ACG = GTV T), (TPH AQ = Cons), (TPH ACL, TPH AFT), (TPH BE = Cons), (TPH AW = PatternMatchingListAppend), (TPH BD = List), (TPH AA = Cons), (TPH AZ = Cons), (TPH BI < TPH BG), (TPH AR < TPH ACK), (TPH AX = Cons), (TPH AT, TPH ACK), (TPH AY, TPH AU), (TPH AFV = GTV T), (TPH AS = ? extends Cons), (TPH BA = Cons), (TPH AFU = GTV T), (TPH AR < TPH AFT)]]

Nur TPH AS = ? extends Empty), TPH AS = ? extends Cons sind die Wildcards falsch.
Hier muss beim generieren der TPHs wildcardable aof false setzt werden.

Das Ergebnis ist dann

public Cons append(Cons(a, Empty b), Empty list2) {
        return new Cons<>(a, append(b, list2));
    }

public Cons append(Cons(a, Empty b), Cons list2) {
        return new Cons<>(a, append(b, list2));
    }

public <AU> append(Cons(a, Cons b),AU list2) {
        return new Cons<>(a, append(b, list2));
    }

public empty append(Empty(), Empty list2) {
        return list2;
    }

public Cons append(Empty(), Cons list2) {
        return list2;
    }

public <BG> BG append(Empty(), BG list2) {
        return list2;
    }
Das Ergebis ist fast richtig: [(TPH ACG = GTV T), (TPH ACI = GTV T), (TPH AQ = Cons<TPH AFI>), (TPH BI = Empty<TPH AFI>), (TPH AU = Empty<TPH AFI>), (TPH AC = Cons<GTV T>), (TPH AFO, TPH AFJ), (TPH BG = Empty<TPH AFI>), (TPH BD = List<GTV T>), (TPH AFL, TPH AFI), (TPH ACL, TPH AFI), (TPH AS = ? extends Empty<TPH AFJ>), (TPH AR < TPH AFI), (TPH AR < TPH AFJ), (TPH AT, TPH AFJ), (TPH BC = GTV T), (TPH AFN = GTV T), (TPH BA = Empty<TPH AFI>), (TPH AFM = GTV T), (TPH AA = Cons<GTV T>), (TPH AZ = Empty<TPH AFI>), (TPH AY = Empty<TPH AFI>), (TPH AX = Empty<TPH AFJ>), (TPH AW = PatternMatchingListAppend), (TPH AFK, TPH AFI), (TPH ACK, TPH AFJ), (TPH BE = Cons<GTV T>)], [(TPH BC = GTV T), (TPH AFQ = GTV T), (TPH AR < TPH AFJ), (TPH AFP, TPH AFH), (TPH BE = Cons<GTV T>), (TPH BA = Cons<TPH AFH>), (TPH AR < TPH AFH), (TPH AFR = GTV T), (TPH AS = ? extends Empty<TPH AFJ>), (TPH AX = Empty<TPH AFJ>), (TPH AA = Cons<GTV T>), (TPH AY = Cons<TPH AFH>), (TPH ACG = GTV T), (TPH AFS, TPH AFJ), (TPH AZ = Cons<TPH AFH>), (TPH AFG, TPH AFH), (TPH ACK, TPH AFJ), (TPH BI = Cons<TPH AFH>), (TPH AC = Cons<GTV T>), (TPH ACI = GTV T), (TPH BD = List<GTV T>), (TPH AU = Cons<TPH AFH>), (TPH AT, TPH AFJ), (TPH AQ = Cons<TPH AFH>), (TPH AW = PatternMatchingListAppend), (TPH ACL, TPH AFH), (TPH BG = Cons<TPH AFH>)], [(TPH AFX, TPH AFT), (TPH BC = GTV T), (TPH AC = Cons<GTV T>), (TPH ACI = GTV T), (TPH AFW, TPH ACK), (TPH ACG = GTV T), (TPH AQ = Cons<TPH AFT>), (TPH ACL, TPH AFT), (TPH BE = Cons<GTV T>), (TPH AW = PatternMatchingListAppend), (TPH BD = List<GTV T>), (TPH AA = Cons<GTV T>), (TPH AZ = Cons<TPH AFT>), (TPH BI < TPH BG), (TPH AR < TPH ACK), (TPH AX = Cons<TPH ACK>), (TPH AT, TPH ACK), (TPH AY, TPH AU), (TPH AFV = GTV T), (TPH AS = ? extends Cons<TPH ACK>), (TPH BA = Cons<TPH AFT>), (TPH AFU = GTV T), (TPH AR < TPH AFT)]] Nur TPH AS = ? extends Empty<TPH AFJ>), TPH AS = ? extends Cons<TPH ACK> sind die Wildcards falsch. Hier muss beim generieren der TPHs wildcardable aof false setzt werden. Das Ergebnis ist dann ```java public Cons append(Cons(a, Empty b), Empty list2) { return new Cons<>(a, append(b, list2)); } public Cons append(Cons(a, Empty b), Cons list2) { return new Cons<>(a, append(b, list2)); } public <AU> append(Cons(a, Cons b),AU list2) { return new Cons<>(a, append(b, list2)); } public empty append(Empty(), Empty list2) { return list2; } public Cons append(Empty(), Cons list2) { return list2; } public <BG> BG append(Empty(), BG list2) { return list2; } ```
Author
Owner

Die Fälle mit Object sind also doch richtig?

Die Fälle mit Object sind also doch richtig?
Owner

Ja, ich bin zu neuen Einsichten gekommen, melde mich später

Ja, ich bin zu neuen Einsichten gekommen, melde mich später
Author
Owner

Ich meine es kann so auch noch nicht funktionieren:

public <AU> append(Cons(a, Cons b),AU list2) {
        return new Cons<>(a, append(b, list2));
    }

Die Funktion führt sich ja selbst rekursiv auf, es gibt aber keine Funktion

public Cons append(Cons(a, Empty b),AU list2) {
        return new Cons<>(a, append(b, list2));
    }

welche die Rekursion terminieren würde.
Außerdem müsste diese Funktion Cons zurückgeben und nicht Object.

Also insgesamt:

public Cons append(Cons(a, Empty b), Empty list2) {
        return new Cons<>(a, append(b, list2));
    }

public Cons append(Cons(a, Cons b), Empty list2) {
        return new Cons<>(a, append(b, list2));
    }

// Bridge Methode:
public Cons append(Cons a, Empty list2) { ... }

public Cons append(Cons(a, Empty b), Cons list2) {
        return new Cons<>(a, append(b, list2));
    }

public Cons append(Cons(a, Cons b), Cons list2) {
        return new Cons<>(a, append(b, list2));
    }

// Bridge Methode:
public Cons append(Cons a, Cons list2) { ... }

public Empty append(Empty(), Empty list2) {
        return list2;
    }

public Cons append(Empty(), Cons list2) {
        return list2;
    }

// Bridge Methode für die ersten 6
public List append(List a, List list2) {
    switch(a) {
         case Empty -> ...
         case Cons -> ...
    }
}

public Cons append(Cons(a, Cons b),AU list2) {
        return new Cons<>(a, append(b, list2));
    }

public Cons append(Cons(a, Empty b),AU list2) {
        return new Cons<>(a, append(b, list2));
    }

// Bridge Methode:
public Cons append(Cons a, AU list2) { ... }

public <BG> BG append(Empty(), BG list2) {
        return list2;
    }

// Bridge Methode für die nächsten drei
// Technisch gesehen braucht es nur diese vier Methoden um alle Fälle abzudecken
public Object append(List cons, Object list2) {
    switch(cons) {
         case Cons(a, Cons b) -> ...
         case Cons(a, Empty b) -> ...
         case Empty() -> ...
    }
}

Ich glaube das würde wirklich alle Fälle abdecken.

Also im Prinzip gibt es drei verschiedene Fälle:

append(List, Cons)
append(List, Empty)
append(List, Object)

und generiert wird noch:

append(List, List)
Ich meine es kann so auch noch nicht funktionieren: ```java public <AU> append(Cons(a, Cons b),AU list2) { return new Cons<>(a, append(b, list2)); } ``` Die Funktion führt sich ja selbst rekursiv auf, es gibt aber keine Funktion ```java public Cons append(Cons(a, Empty b),AU list2) { return new Cons<>(a, append(b, list2)); } ``` welche die Rekursion terminieren würde. Außerdem müsste diese Funktion `Cons` zurückgeben und nicht Object. Also insgesamt: ```java public Cons append(Cons(a, Empty b), Empty list2) { return new Cons<>(a, append(b, list2)); } public Cons append(Cons(a, Cons b), Empty list2) { return new Cons<>(a, append(b, list2)); } // Bridge Methode: public Cons append(Cons a, Empty list2) { ... } public Cons append(Cons(a, Empty b), Cons list2) { return new Cons<>(a, append(b, list2)); } public Cons append(Cons(a, Cons b), Cons list2) { return new Cons<>(a, append(b, list2)); } // Bridge Methode: public Cons append(Cons a, Cons list2) { ... } public Empty append(Empty(), Empty list2) { return list2; } public Cons append(Empty(), Cons list2) { return list2; } // Bridge Methode für die ersten 6 public List append(List a, List list2) { switch(a) { case Empty -> ... case Cons -> ... } } public Cons append(Cons(a, Cons b),AU list2) { return new Cons<>(a, append(b, list2)); } public Cons append(Cons(a, Empty b),AU list2) { return new Cons<>(a, append(b, list2)); } // Bridge Methode: public Cons append(Cons a, AU list2) { ... } public <BG> BG append(Empty(), BG list2) { return list2; } // Bridge Methode für die nächsten drei // Technisch gesehen braucht es nur diese vier Methoden um alle Fälle abzudecken public Object append(List cons, Object list2) { switch(cons) { case Cons(a, Cons b) -> ... case Cons(a, Empty b) -> ... case Empty() -> ... } } ``` Ich glaube das würde wirklich alle Fälle abdecken. Also im Prinzip gibt es drei verschiedene Fälle: ``` append(List, Cons) append(List, Empty) append(List, Object) ``` und generiert wird noch: ``` append(List, List) ```
Sign in to join this conversation.
No Milestone
No project
No Assignees
2 Participants
Notifications
Due Date
The due date is invalid or out of range. Please use the format 'yyyy-mm-dd'.

No due date set.

Dependencies

No dependencies set.

Reference: JavaTX/JavaCompilerCore#355
No description provided.