Hi, ich versuche gerade Haskell zu lernen und habe auch gleich eine Frage. Wie kann man einen neuen Operator definieren? Also z.B. && Dabei gilt folgendes:
True && True = True _ && _ = False
1. Wie bekommt man eine "Funktion" zwischen 2 Werte? 2. Wie prüfe ich die Bedingungen?
[Hinweis: Ich habe gerade kein Haskell installiert, daher alles ungetestet!]
Zunächst einmal: ein binärer Operator ist nichts anderes als eine Funktion mit zwei Parametern, mit dem einzigen Unterschied, dass ein Operator zwischen den Operanden steht statt davor. Und umgekehrt: eine Funktion mit zwei Parametern ist nichts anderes als ein binärer Operator, der vor die Operanden geschrieben wird.
Man kann einen Operator wie eine Funktion behandeln, indem man ihn in Klammern einschließt und man kann eine Funktion wie einen Operator behandeln, indem man sie in Backticks einschließt.
1 + 2 (+) 1 2
div 4 2 4 `div` 2
Die beiden Zeilen bedeuten jeweils dasselbe.
Die Tatsache, dass man einen Operator wie eine Funktion behandeln kann, indem man ihn in Klammern einschließt, gilt immer, das heißt auch für Funktionsdefinitionen, nicht nur Funktionsaufrufe. Mit anderen Worten: man kann einen Operator genau wie eine Funktion definieren, wenn man ihn wie eine Funktion behandelt.
(&&) a b = blah
Jetzt noch zur letzten Frage: wie prüft man die Bedingungen? Die Antwort ist: gar nicht! Wir lassen Haskell die Arbeit für uns machen! (Dafür sind Computer schließlich da.) Wir benutzen Pattern Matching und partielle Funktionsdefinitionen:
(&&) True True = True (&&) _ _ = False
EDIT: Diese Definition ist nicht ganz korrekt. Das zweite Argument muss immer ausgewertet werden, was in Wirklichkeit nicht der Fall ist, denn wenn das erste Argument False ist, dann ist das zweite Argument irrelevant und muss nicht ausgewertet werden (das Ergebnis ist immer False) und wenn das erste Argument True ist, dann ist der Rückgabewert das zweite Argument und es muss wieder nicht ausgewertet werden sondern nur zurückgegeben. Die korrekte Definition lautet also:
(&&) True b = b (&&) False _ = False
Und noch etwas: man muss gar nicht die Funktionssyntax für die Definition verwenden (nur für Typdeklarationen), also kann man die Definition auch so schreiben:
Ergänzend zu Jörgs Antwort sei noch angemerkt, dass du "Bindungskraft" (á la "Punktrechnung vor Strichrechnung") und Assoziativität (Wird a # b # c als (a # b) # c oder a # (b # c) ausgewertet?) einer Operation ebenfalls angeben kannst:
3.2.2 Fixity Declarations
A fixity declaration can be given for any infix operator or constructor (including those made from ordinary identifiers, such as `elem`). This declaration specifies a precedence level from 0 to 9 (with 9 being the strongest; normal application is assumed to have a precedence level of 10), and left-, right-, or non-associativity. For example, the fixity declarations for ++ and . are:
infixr 5 ++ infixr 9 .
Both of these specify right-associativity, the first with a precedence level of 5, the other 9. Left associativity is specified via infixl, and non-associativity by infix. Also, the fixity of more than one operator may be specified with the same fixity declaration. If no fixity declaration is given for a particular operator, it defaults to infixl 9.