fmidue / logic-tasks

0 stars 1 forks source link

Feedback teilweise von partialGrade nach completeGrade verschieben #88

Closed nimec01 closed 7 months ago

nimec01 commented 7 months ago

Wie in #68 bereits angesprochen, verrät das Feedback von partialGrade teilweise die Lösung. Demnach habe ich einige Rückmeldungen nach completeGrade verschoben.

jvoigtlaender commented 7 months ago

Beim Resolve-Aufgabentyp wäre ich durchaus dafür, zumindest optional (durch Lehrenden konfigurierbar) das Feedback zu der Korrektheit der Schritte etc. auch schon in partialGrade zu aktivieren. Einfach weil die Aufgabe an sich kompliziert ist und vorstellbar ist, dass wir für sie ein inkrementelles Lösen ermöglichen wollen, also dass die Studierenden sich dabei vom System helfen lassen. (Beobachtung: Im aktuellen Durchlauf hat eine Person zur selben Aufgabe diesen Typs über 700 Einreichungen gemacht. Eventuell hat hier das System die Rolle des Lehrenden übernommen. Die Punkte sind dann durch "Leaking" entstanden, aber sicher wurde etwas gelernt, also ist das ein machbarer Tradeoff. Was denkst du, @owestphal?)

nimec01 commented 7 months ago

Eine Sache, die mir noch nicht so ganz gefällt, ist die Nutzung von preventWithHint. Wenn man z.B. folgenden Code betrachtet

preventWithHint (missingLen > solLen)
    (translate $ do
      german "Lösung hat genügend Werte?"
      english "Solution contains enough values?"
    )
    (translate $ do
      german "Lösung enthält zu wenige Werte."
      english "Solution does not contain enough values."
    )

preventWithHint (not (solLen == tableLen || solLen == missingLen))
    (translate $ do
      german "Lösung hat korrekte Länge?"
      english "Solution has correct length?"
    )
    (translate $ do
      german $ "Die Lösung muss genau "  ++ show missingLen ++ " Lücken enthalten."
      english $ "The solution must contain exactly " ++ show missingLen ++ " gaps."
    )

wird der zweite Aufruf von preventWithHint keinen Text ausgeben, falls der erste Aufruf ein Hint geprintet hat (und somit die Lösung rejected wird).

Hier ein Ausschnitt aus einem Test: image

nimec01 commented 7 months ago

Des Weiteren sind mir nochmal ein paar Ungereimtheiten in Hinsicht auf #78 aufgefallen. Bei einer Aufgabe wird z.B. trotz richtiger Lösung nochmal eine mögliche Lösung angezeigt. Das sollte (eventuell zusammen mit möglichen Änderungen bzgl. des letzten Kommentars) noch einmal evaluiert werden.

jvoigtlaender commented 7 months ago

Bzgl. der Sache mit

preventWithHint (missingLen > solLen)

und

preventWithHint (not (solLen == tableLen || solLen == missingLen))

oben vermute ich, dass es Absicht ist, dass der erste Hinweis den zweiten deaktiviert.

Hintergrund dürfte sein, dass hier ein häufiger Fehleingabefall speziell abgefangen (bzw. gezielt uminterpretiert) wird.

Die Aufgabe verlangt eigentlich die Angabe von nur den Lücken. Also sagen wir, es gab drei Eingaben, folglich 8 Zeilen der Wahrheitstafel. Darin sind 3 Lücken. Eigentlich sollen die Studierenden nun also eine dreielementige Liste einreichen. Manche aber übersehen, dass sie nur die Lücken angeben sollen und reichen stattdessen eine achtelementige Liste ein. Da das so oft vorkam, wurde der Aufgabentyp so umgeschrieben, dass er das akzeptiert. Daraufhin ist auch die Eingabebehandlung speziell.

Wenn also jemand eine zweielementige Liste einreicht, wird ihm nur gesagt, dass sie zu kurz ist (sie wäre zu kurz, egal ob eigentlich drei oder acht Elemente einzugeben gewesen wären).

Wenn jemand eine fünfelementige Liste einreicht, wird gesagt, dass eine dreielementige Liste erwartet wurde.

Wenn jemand eine achtelementige Liste einreicht, wird das hingenommen und diese Eingabe dann bei der Bewertung speziell behandelt.

Würde es unter diesen Gesichtspunkten wirklich Sinn ergeben, bei der Eingabe einer zweielementigen Liste beide Hinweise zu geben?

jvoigtlaender commented 7 months ago

Bzgl.

Des Weiteren sind mir nochmal ein paar Ungereimtheiten in Hinsicht auf https://github.com/fmidue/logic-tasks/pull/78 aufgefallen.

wäre vielleicht am besten, das in einem separaten Issue zu dokumentieren.

nimec01 commented 7 months ago

Vielleicht war mein Beispiel zu preventWithHint unpassend gewählt, aber worauf ich hinaus wollte: Bei completeGrade hat der Studierende keine Möglichkeiten mehr die Abgabe anzupassen. Wäre es dann nicht sinnvoll, die Ergebnisse aller Checks (eventuell mit Ausnahmen) dort auch anzuzeigen? Es würde ihm/ihr ja nichts nützen nur zu wissen, dass die Lösung z.B. zu wenig Werte beinhaltet. Da der letzte preventWithHint Aufruf auch noch die Aufgabe hat, falls entsprechend konfiguriert, eine mögliche Lösung anzuzeigen, ist dies auch problematisch. Diese würde dann nämlich nicht angezeigt werden.

jvoigtlaender commented 7 months ago

Dies:

Da der letzte preventWithHint Aufruf auch noch die Aufgabe hat, falls entsprechend konfiguriert, eine mögliche Lösung anzuzeigen, ist dies auch problematisch. Diese würde dann nämlich nicht angezeigt werden.

verstehe ich wiederum nicht. Inwiefern hat der letzte preventWithHint Aufruf die Aufgabe, eine Lösung anzuzeigen? Sehe ich zumindest in dem Beispiel nicht. Oder geht es darum, dass in einem späteren Teil desselben do-Blocks (aber nicht in dem preventWithHint) die Lösungsausgabe erfolgt?

Und zudem: Ist die Sache mit den Hinweisen zur Lückenanzahl überhaupt Teil von completeGrade? Ist das nicht in partialGrade, wo irgendeine Lösungsausgabe sowieso nicht infrage kommt?

Ich glaube, wir müssten mal genauer schauen, um welche konkrete Aufgabe es geht. Vielleicht ist das Problem einfach, dass zu viel von partialGrade nach completeGrade verschoben wurde.

nimec01 commented 7 months ago

Bei Decide sieht completeGrade wie folgt aus

completeGrade :: OutputMonad m => DecideInst -> [Int] -> LangM m
completeGrade DecideInst{..} sol = do
  preventWithHint (solLen > acLen)
    (translate $ do
      german "Lösung enthält nicht zu viele Indizes?"
      english "Solution does not contain too many indices?"
    )
    (translate $ do
      german "Lösung enthält zu viele Indizes."
      english "Solution contains too many indices."
    )

  preventWithHint (acLen > solLen)
    (translate $ do
      german "Lösung enthält genügend Indizes?"
      english "Solution contains enough indices?"
    )
    (translate $ do
      german "Lösung enthält zu wenige Indizes."
      english "Solution does not contain enough indices."
    )

  preventWithHint (diff /= 0)
    (translate $ do
      german "Lösung ist korrekt?"
      english "Solution is correct?"
    )
    (do
      translate $ do
        german $ "Die Lösung beinhaltet " ++ display ++ " Fehler."
        english $ "Your solution contains " ++ display ++ " mistakes."
      when showSolution $ example (show changed) $ do
        english "A possible solution for this task is:"
        german "Eine mögliche Lösung für die Aufgabe ist:"
      pure ()
    )

  pure ()
  where
    nubSol = nub sol
    diff = length $ filter (`notElem` changed) nubSol
    acLen = length $ nub changed
    solLen = length $ nub sol
    distance = abs (solLen - acLen)
    display = show distance

Mal angenommen ein Student reicht die Lösung [1] ein und printFeedback = True. Dann sieht das Feedback wie folgt aus: image

Die Aufgabe wurde nun bewertet und der Student sieht nur, dass ihm noch einige Indizes fehlen. Da acLen > solLen == True, wird hier die Lösung abgelehnt und kein weiteres Feedback (außer dem entsprechenden Hint) ausgegeben. Demnach geht "Lösung ist korrekt?" verloren, was bei einer falschen Lösung dazu führen würde, dass "Eine mögliche Lösung für die Aufgabe ist" ausgegeben wird.

nimec01 commented 7 months ago

Ähnlich ist dies bei Fill der Fall. Die Instanz hat hier 6 Lücken und printFeedback = True. image Natürlich hat der Student hier zu viele Werte angegeben, allerdings sollte das Feedback trotzdem angezeigt werden. Mit der aktuellen Umsetzung mit preventWithHint ist das allerdings nicht so einfach umzusetzen.

jvoigtlaender commented 7 months ago

Bei Decide sehe ich das Problem. Die Lösung wäre wohl einfach, die beiden Teile preventWithHint (solLen > acLen) und preventWithHint (acLen > solLen) jeweils durch geeignete Aufrufe von yesNo zu ersetzen.

jvoigtlaender commented 7 months ago

Bei Fill sollte sich das Problem dadurch auflösen, dass die Teile preventWithHint (missingLen > solLen) und preventWithHint (not (solLen == tableLen || solLen == missingLen)) zurück nach partialGrade verschoben werden. Sie "leaken" ja gar keine Information, da die Anzahl der Lücken in der Aufgabenstellung sowieso schon "verraten" wird (während bei Decide nicht der Fall ist, dass die Aufgabenstellung die Anzahl der Fehler preisgibt).

jvoigtlaender commented 7 months ago

Siehe auch noch https://github.com/nimec01/logic-tasks/pull/1