Haskell lernen und aufkommende Fragen.
-
Th69 schrieb:
da hast du dir aber etwas vorgenommen, Haskell als erste Programmiersprache zu erlernen: m.E. ist es nicht so einfach gleich funktional und rekursiv zu denken (da einem sequentielle Abläufe ersteinmal einfacher erscheinen).
Es gibt da ja auch die Meinung, dass man funktionale Programmierung viel einfacher verstehen würde, wenn man vorher nicht imperativ "verseucht" ist. Es fasziniert mich daher etwas, hier Haskell als erste Programmiersprache sozusagen in freier Wildbahn beobachten zu können.
Und das "Eq k" soll (wohl) heißen, daß k ein Typ sein muß, der "vergleichbar" (equatable) ist, sonst kann man nicht die "lookup"-Funktion bzw. den gleich/ungleich-Operator benutzen.
Ja, der Begriff ist Typklasse. Das
Eq k =>
heißt, dass der Typ k eine Instanz der Typklasse Eq sein muss.Eine Sache, die noch offen war: Es kam die Frage auf, was das (D l) in der Argumentliste bedeutet. Das ist Pattern Matching. Man könnte auch
einfuegen x y = ...
Ruft man dann
einfuegen (3, "baz") (D [(1, "foo"), (2, "bar")])
auf, ist
x = (3, "baz")
undy = (D [(1, "foo"), (2, "bar")])
. Durch Angabe von (D l) statt y gilt diese Definition erstens nur für Aufrufe, bei denen für das zweite Argument der Typkonstruktor D benutzt wurde (wäre relevant, wenn es mehr als diesen einen gäbe), zweitens wird die Liste gleich "ausgepackt". Miteinfuegen x (D l) = ...
ist dann gleich
l = [(1, "foo"), (2, "bar")]
-
Vielen Dank für die Antworten!
Das muss ich nun erst mal verarbeiten. Weitere Fragen werden heute also nicht mehr kommenSchönen Abend noch.
-
So ich bin das mal durchgegangen und habe natürlich noch ein paar Fragen.
Was ich mich plötzlich Frage ist: Wozu überhaupt zwei Module? Das Modul Adressbuch macht doch das gleiche wie das Modul Woerterbuch.
newtype WBuch k v = D [(k,v)] deriving Show
Also WBuch ist ja der Name des Typs aber heißt der Typ dann nicht WBuch k v?
Würde dann nicht newtype WBuch = D... ausreichen?leeresBuch :: Eq k=> WBuch k v leeresWBuch = D []
Bei dieser Funktion wird kein Parameter erwartet. Wenn sie aufgerufen wird, wird eine leere Liste erzeugt.
Aber wenn doch eh kein Wert zur Übergabe erwartet wird, wieso muss der Wert dann zu der Klasse Eq angehören?einfuegen :: (k, v) -> WBuch k v -> WBuch k v einfuegen x (D l) = D (x:l)
Wenn ich für "D" auch [(k,v)] schreiben könnte, würde die Funktion dann so lauten:
einfuegen x ([(k,v)] l) = [(k,v)] (x:l)
oder habe ich das zu wörtlich genommen?
finde :: Eq k => k -> WBuch k v -> Maybe v finde k (D l) = lookup k l
Also wenn lookup ein Nothing ausgibt soll stattdessen Maybe v ausgegeben werden.
Das passiert aber doch nur, wenn er die entsprechende Adresse in der Liste nicht findet. Würde er dann einfach einen willkürlichen Wert aus der Liste ausgeben? Ich bin mir hier nicht so wirklich im klaren, was für einen Wert Maybe v haben kann/soll.loesche :: Eq k => k -> WBuch k v -> WBuch k v loesche key (D l) = D [(k,v) | (k,v) <- l, k/=key]
Wenn ich eine neue Liste erzeuge unter der Bedingung, dass das bisherige Element ungleich dem übergebenen Element ist, woher weiß die Funktion dann, welchen Wert ich löschen soll wenn doch das Element gar nicht in der Liste existiert?
Ich übergebe der Funktion den Wert "Schmidt" also steht in key=Schmidt.
Also soll der Eintrag Schmidt gelöscht werden. In der Funktion steht aber doch nur, das Schmidt ungleich dem Wert "k" sein soll und dann wird eine neue Liste l erstellt. Nur hat "l" doch genau den gleichen Inhalt wie vorher auch.
-
Ui, da hast du wirklich noch einige Verständnisschwierigkeiten.
0. Ich denke die beiden Module wurden einfach gewählt, damit man sieht wie diese in Haskell benutzt werden können, so daß ein "Datenaustausch" zwischen Wörterbuch und Adressbuch gezeigt werden kann
1. die Variablen k und v müssen einfach angegeben werden, damit sie auf der rechten Seite benutzt werden können (sonst Compilerfehler)
2. hierauf kann ich dir keine eindeutige Antwort geben, aber du kannst ja mal ausprobieren was passiert, wenn du das "Eq k" entfernst.
3. Nicht für D kann man [(k,v)] schreiben, sondern für l (hast du mein Beispiel dazu nicht richtig gelesen?)
4. Maybe v kannst du dir wie einen Typen vorstellen, der entweder v oder aber ein "Nothing" bzw. "NIL" (not in list
zurückgibt - in anderen Sprachen benutzt man z.B. "optional" oder "nullable" o.ä. dafür).
5. Es wird eben eine neue Liste erstellt, mit der Bedingung, daß nur die Werte kopiert werden, welche ungleich dem übergebenen key sind (und somit eine Liste, aus der alle key-Elemente gelöscht wurden) - aber auch dies hatte ich schon geschrieben
Vllt. solltest du auch nicht gleich diesen kompletten Code benutzen, sondern sukzessive die einzelnen Funktionen erstellen und entsprechend praktisch anwenden.
-
Schmidto schrieb:
leeresBuch :: Eq k=> WBuch k v leeresWBuch = D []
Bei dieser Funktion wird kein Parameter erwartet. Wenn sie aufgerufen wird, wird eine leere Liste erzeugt.
Aber wenn doch eh kein Wert zur Übergabe erwartet wird, wieso muss der Wert dann zu der Klasse Eq angehören?Für diese Funktion wird das eigentlich nicht benötigt. Aber wenn du es weglässt, kann man damit WBuch-Werte mit nicht vergleichbaren Schlüsseln erzeugen, bei denen dann kein lookup möglich ist.
-
Danke für die Antworten.
Ich bin schon dabei jede Funktion einzelnd zu testen und aber natürlich auch zu verstehen..@ TH69
gelesen habe ich deinen Beitrag aber anscheind habe ich das ein oder andere einfach nur falsch interpretiert.
-
Bashar schrieb:
Es gibt da ja auch die Meinung, dass man funktionale Programmierung viel einfacher verstehen würde, wenn man vorher nicht imperativ "verseucht" ist.
ist das in einem Experiment von signifikantem Umfang ausprobiert worden ?
das würde u.a. implizieren, daß man die kategorientheoretischen Monaden viel einfacher verstehen würde ohne Vorkenntnisse über Imperatives wie print und printf.
-
buchstaben schrieb:
Bashar schrieb:
Es gibt da ja auch die Meinung, dass man funktionale Programmierung viel einfacher verstehen würde, wenn man vorher nicht imperativ "verseucht" ist.
ist das in einem Experiment von signifikantem Umfang ausprobiert worden ?
Keine Ahnung, vermutlich nicht. Mir sind überhaupt keine Experimente zum Thema Lernen und Verstehen von Programmiersprachen bekannt, nur Meinungen.
-
Bashar schrieb:
Für diese Funktion wird das eigentlich nicht benötigt. Aber wenn du es weglässt, kann man damit WBuch-Werte mit nicht vergleichbaren Schlüsseln erzeugen, bei denen dann kein lookup möglich ist.
Wie kann ich denn mit der Funktion nicht vergleichbare Schlüssel erzeugen, wenn ich am Ende doch nur eine leere Liste D [] bekomme?
Und 'newtype' legt einen neuen Datentyp an, wobei im Beispiel 'D' einfach nur ein selbstgewählter Bezeichner steht (D steht wohl für Dictionary). Sicherlich hätte man auch überall im weiteren Code einfach nur [(k,v)] schreiben können (aber dann hätte man die gleichen Lese-Probleme wie ohne die Verwendung von Aliasnamen).
das hatte ich so verstanden, dass ich einfach das "D" überall mit [(k,v)] ersetzen könnte
-
Aber nicht für das 'D' alleine, sondern für den gesamten Datentyp (D l).
-
ok verstanden
4. Maybe v kannst du dir wie einen Typen vorstellen, der entweder v oder aber ein "Nothing" bzw. "NIL" (not in list
zurückgibt - in anderen Sprachen benutzt man z.B. "optional" oder "nullable" o.ä. dafür).
Also wnen Maybe ein Typ ist aber v den selben Typen hat wie k.. dann ergibt das maybe doch gar keinen Unterschied
finde :: Eq k => k -> WBuch k v -> k
wäre dann doch das gleiche.
-
Also mit den neuen Informationen, versuche ich mal nun folgende Funktion zu erklären:
einfuegen :: (Name, Adresse) -> Adressbuch -> Adressbuch einfuegen x = fromWBuch . W.einfuegen x . toWBuch
Es wird die Funktion einfuegen im Modul Woerterbuch aufgerufen.
Diese Funktion erwartet als Eingabe folgende Typen:einfuegen :: (k, v) -> WBuch k v -> WBuch k v einfuegen x (D l) = D (x:l)
Name und Adresse sind also (a,b)
Leider fällt es mir jetzt schon sehr schwer, den weiteren Ablauf zu erklären. In der Signatur steht,
dass nun der Typ Adressbuch erwartet wird und dieser wird wohl mit fromWBuch übergeben.
Aber die Funktion einfuegen im Woerterbuch benötigt doch den Typ WBuch also toWBuch.
"W.einfuegen x . toWBuch" diese zwei Werte werden doch an die Funktion einfuegen aus dem Woerterbuch übergeben.
Durch toWBuch wird auch der passende Typ übergeben.
Aber wozu brauch ich denn das fromWBuch?
Auch die Signatur aus der Funktion einfuegen im Adressbuch verstehe ich nicht so ganz.einfuegen :: (Name, Adresse) -> Adressbuch -> Adressbuch
am Ende kommt doch der Typ WBuch raus und nicht Adressbuch...
-
Es wurde zwar schonmal gesagt, aber du verwechselst
newtype
mittype
.In der Benutzung ist ein Typ mit
newtype
genau das gleiche wie einer mitdata
, stell dir also vor, anstatt newtype stünde überall data.
-
ist mir gar nicht bewusst das ich das tue..
einfuegen :: (Name, Adresse) -> Adressbuch -> Adressbuch einfuegen x = fromWBuch . W.einfuegen x . toWBuch
dieser Teil ist mir ja klar denke ich:
W.einfuegen x . toWBuch
da die Funktion im Wörternuch das x und halt den Typ WBuch benötigt.
das fromWBuch steht ja VOR dem Funktionsaufruf.. durch den "." vor dem "W.einfuegen" wird dadurch der Rückgabetyp von der Funktion W.einfuegen also WBuch dann zu einem Adressbuch?
-
einfuegen :: (Name, Adresse) -> Adressbuch -> Adressbuch einfuegen x = fromWBuch . W.einfuegen x . toWBuch
Erstmal die Signatur analysieren. Der -> Operator ist rechtsassoziativ, sie wird also als
einfuegen :: (Name, Adresse) -> (Adressbuch -> Adressbuch)
verstanden. Übersetzt: einfuegen ist eine Funktion, der man ein Paar (Name,Adresse) übergibt, und die eine Funktion, die ein Adressbuch auf ein Adressbuch abbildet, zurückgibt.
In der Definition sieht man nun den .-Operator für die Komposition von Funktionen. Komposition ist die Hintereinanderausführung von Funktionen, (f . g) x bedeutet f (g x). einfuegen x ergibt also eine Funktion, die auf ihr Argument, ein Adressbuch, zuerst toWBuch anwendet (es kommt ein WBuch heraus), dann auf das Ergebnis die einfuegen-Funktion aus dem Woerterbuch-Modul anwendet (es kommt ein WBuch mit eingefügtem x heraus), auf das Ergebnis dann fromWBuch anwendet (es kommt ein Adressbuch heraus).
Man kann die Signatur von einfuegen auch so verstehen, dass dort zwei Parameter, ein Paar (Name,Adresse) und ein Adressbuch, übergeben werden und ein Adressbuch herauskommt. Das Prinzip des Curryings besagt, dass man Funktionen mit mehreren Argumenten als Funktionen mit einem Argument, die eine weitere Funktion zurückgeben, auffassen kann. Das wäre dann die obige Interpretation. Man hätte einfuegen aber auch in der nicht gecurryten Form schreiben können:
einfuegen :: (Name, Adresse) -> Adressbuch -> Adressbuch einfuegen x a = fromWBuch (W.einfuegen x (toWBuch a))
-
Bashar schrieb:
Th69 schrieb:
da hast du dir aber etwas vorgenommen, Haskell als erste Programmiersprache zu erlernen: m.E. ist es nicht so einfach gleich funktional und rekursiv zu denken (da einem sequentielle Abläufe ersteinmal einfacher erscheinen).
Es gibt da ja auch die Meinung, dass man funktionale Programmierung viel einfacher verstehen würde, wenn man vorher nicht imperativ "verseucht" ist.
Gibts diese Meinung auch außerhalb dieses Forums? Oder ist diese Meinung einfach nur eine Ausrede?
-
Da der Großteil der (programmierenden) Weltbevölkerung nicht in diesem Forum ist, gehe ich davon aus, dass es auch da Menschen gibt, die diese Meinung haben.
Man könnte ja mal eine richtige Studie mit zufallseingeteilten Gruppen usw. machen.
Aber wofür sollte es eine Ausrede sein?Ich fand's auch interessant, dass Schmidto sich Haskell als erste Sprache ausgesucht hat, aber warum auch nicht?
Gerade bei Mathematikern könnte ich mir vorstellen, dass es einige von ihnen intuitiv schneller funktional als imperativ Programmieren können.
-
Dobi schrieb:
Aber wofür sollte es eine Ausrede sein?
Dafür, dass Haskell einfach nicht intuitiv zu erlernen ist. Jetzt versuchen die Haskell Fans sich halt darauf raus zu reden, dass man vorher zuviel imperativ programmiert hat.
-
Dieser Thread wurde von Moderator/in Marc++us aus dem Forum Rund um die Programmierung in das Forum Funktionale Programmiersprachen verschoben.
Im Zweifelsfall bitte auch folgende Hinweise beachten:
C/C++ Forum :: FAQ - Sonstiges :: Wohin mit meiner Frage?Dieses Posting wurde automatisch erzeugt.
-
Da mag wohl jemand functional nicht, wie?
Genau wie für verschiedene Aufgaben verschiedene Programmiersprachen besser oder schlechter geeignet sind, so sind sie es auch für verschiedene Menschen.