Gibt es eine Möglichkeit, "C-Dur" anstelle von "C-Dur" zu schreiben?
Ich bin in meinem Musikprojekt auf ein kleines ästhetisches Problem gestoßen, das mich schon seit einiger Zeit stört.
Ich habe einen Typ Daten Key = C | D | ...
und ich kann eine Scale
aus einem Key
und einem Mode
konstruieren. Der Mode
unterscheidet z.B. zwischen einer Dur- und einer Molltonleiter.
Ich kann den Typ Mode
als eine Funktion von Key
zu Scale
definieren. In diesem Fall haben die Modi Namen in Kleinbuchstaben (was in Ordnung ist) und ich kann eine Skala wie diese erhalten
aScale = major C
Aber Musiker sprechen nicht so. Sie bezeichnen diese Skala als _C-Dur-Tonleiter, nicht als C-Dur-Tonleiter.
Was ich will
Idealerweise würde ich schreiben wollen
aScale = C major
Ist das überhaupt möglich?
Was ich versucht habe
Ich kann Key
zu einer Funktion machen, die eine Scale
aus einem Mode
konstruiert, also kann ich schreiben
aScale = c Major
Aber ich kann Keys nicht auf die Konstruktion von Skalen beschränken. Sie werden auch für andere Dinge benötigt (z.B. für die Konstruktion von Akkorden). Auch Key
sollte eine Instanz von Show
sein.
Ich kann den Mode
nach dem Key
setzen, wenn ich eine zusätzliche Funktion (oder einen Wertkonstruktor) verwende:
aScale = scale C major
mit scale :: Tonart -> Modus -> Skala
Aber das zusätzliche Wort Skala sieht störend aus, und im Gegensatz zu seinem Namen hat Skala
nicht wirklich mit Skalen zu tun. Der intelligente Teil ist in Major
, Skala
ist eigentlich nur flip ($)
.
Die Verwendung eines newtype Mode = Major | Minor ...
ändert nicht wirklich viel, außer dass scale
intelligenter sein muss:
aScale = scale C Major
Lösung 1:
Verwenden Sie diese
Jetzt können Sie schreiben (mit großem C und großem M)
Lösung 2a:
Auch dies ist möglich
Jetzt schreiben Sie
Lösung 2b:
Auch dies ist möglich
Jetzt schreiben Sie
Hier ist eine skurrile Lösung, die ich nicht wirklich empfehle, die aber sehr "musikalisch" aussieht:
Dann können Sie schreiben
Das Ziel ist natürlich, dass man auch
F♯ minor
undB♭ major
usw. hat.Wenn Sie nichts gegen einen zusätzlichen Operator haben, könnten Sie
&
ausData.Function
verwenden. Unter der Annahme, dassmajor
eine FunktionKey -> Scale
ist, könnten SieC & major
schreiben. Das ergibt einenScale
-Wert:Es gibt bereits mehrere gute Antworten, aber hier ist eine Lösung im Stil des Continuation-Passing-Stils, die hilfreich sein könnte (vielleicht nicht für dieses spezielle Beispiel, aber in anderen Kontexten, in denen eine Art Syntax für die umgekehrte Anwendung gewünscht wird).
Mit Standarddefinitionen für einige Problemdomänentypen:
können Sie einen Continuation-Passing-Typ einführen:
und schreibe die primitiven Notizbau-Typen, um `Content'-Typen wie diese zu bauen:
Dann können die Tonleiter-, Noten- und Akkordbildungsfunktionen die
Cont's in einfache Typen in jeder Postfix-Form auflösen (d.h. als Fortsetzungen, die an die
Cont's übergeben werden):oder Präfix-Form (d.h. unter Verwendung von
Content
als Argument):Jetzt können Sie schreiben:
Beachten Sie, dass
c
selbst keineShow'-Instanz hat, aber
c note` schon.Mit einer Modifikation des
Note
-Typs könnten Sie leicht doppelte Vorzeichen unterstützen (z.B.cis sharp
, verschieden vond
), usw.Sie können Typklassen verwenden, um das geschickt zu umgehen:
Jetzt können Sie die Kleinbuchstaben auch für andere Typen verwenden, indem Sie entsprechende Instanzen definieren.