Ich bin in meinem Musikprojekt auf ein kleines ästhetisches Problem gestoßen, das mich seit einiger Zeit nervt.
Ich habe einen Typ data Key = C | D | ...
und kann einen Scale
aus a Key
und a konstruieren Mode
. Das Mode
unterscheidet zB eine Dur- und eine Moll-Tonleiter.
Ich kann den Mode
Typ als Funktion von Key
bis definieren Scale
. In diesem Fall haben die Modi Kleinbuchstaben (was in Ordnung ist) und ich kann eine solche Skala erhalten
aScale = major C
Aber Musiker reden nicht so. Sie beziehen sich auf dieser Skala als die C - Dur - Tonleiter, nicht die C - Dur - Skala.
Was ich möchte
Idealerweise möchte ich schreiben
aScale = C major
Ist das überhaupt möglich?
Was ich versucht habe
Ich kann Key
eine Funktion erstellen, die a Scale
aus a konstruiert Mode
, damit ich schreiben kann
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. zum Erstellen von Akkorden ). Sollte Key
auch eine Instanz von sein Show
.
Ich kann das Mode
nach dem setzen, Key
wenn ich eine zusätzliche Funktion (oder einen Wertkonstruktor) verwende:
aScale = scale C major
mit scale :: Key -> Mode -> Scale
Aber die zusätzliche Wortskala sieht laut aus und befasst sich entgegen ihrem Namen scale
nicht wirklich mit Skalen. Der intelligente Teil ist in major
, scale
ist wirklich gerecht flip ($)
.
Die Verwendung von a newtype Mode = Major | Minor ...
ändert sich nicht wirklich, außer scale
dass es intelligenter sein muss:
aScale = scale C Major
major C
.Antworten:
Lösung 1:
Benutze das
Jetzt können Sie schreiben (mit Großbuchstaben C und Großbuchstaben M)
Lösung 2a:
Dies ist auch möglich
Jetzt schreibst du
Lösung 2b:
Dies ist auch möglich
Jetzt schreibst du
quelle
Hier ist eine skurrile Lösung, die ich nicht wirklich empfehle, die aber sehr "musikalisch" aussieht:
Dann kannst du schreiben
Natürlich, wo dies wirklich angestrebt wird, ist, dass Sie auch haben
F♯ minor
undB♭ major
etc ..quelle
⠀
U + 2800 BRAILLE PATTERN BLANK kann als Infix verwendet werden. Unnötig zu sagen, dass dies eine schreckliche Idee ist ... Alle tatsächlichen Leerzeichen sind als Infixe verboten, aber es überrascht nicht, dass Unicode etwas enthält, das in den Missbrauchszweck gehackt werden kann.Wenn Ihnen ein zusätzlicher Operator nichts ausmacht, können Sie
&
von verwendenData.Function
. Angenommen, diesmajor
ist eine FunktionKey -> Scale
, könnten Sie schreibenC & major
. Das ergibt einenScale
Wert:quelle
Es gibt bereits mehrere gute Antworten, aber hier ist eine Lösung für die Weitergabe, die hilfreich sein kann (möglicherweise 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:
Sie können einen Continuation-Passing-Typ einführen:
und schreiben Sie die primitiven Notizenbildungstypen, um
Cont
Typen wie diese zu erstellen :Dann können die Funktionen zum Erstellen von Skalen, Noten und Akkorden die
Cont
s in einfache Typen in jeder Postfix-Form auflösen (dh als Fortsetzung, die an die übergeben werden sollCont
):oder Präfixform (dh
Cont
s als Argumente nehmen):Jetzt können Sie schreiben:
Beachten Sie, dass es
c
selbst keineShow
Instanz gibt, dies aberc note
tut.Mit einer Änderung des
Note
Typs könnten Sie leicht doppelte Vorzeichen (z. B.c sharp sharp
verschieden vond
) usw. unterstützen.quelle
Cont
aber ich habe versucht, es an die Konstruktoren zu kleben,A | B | C ...
anstatt Funktionen zu verwenden. Ich konnte das nicht zum Laufen bringen und verstehe immer noch nicht warum, da Wertekonstruktoren nur Funktionen sind. Wenn ich eine Funktion vor meine Schlüssel stecken kann, werden viele Dinge möglich. Wenn die Funktionflip ($)
dann ist, bekomme ich Ihr Musterflip ($) B :: Cont Key r
. Mein OriginalaScale = scale C Major
ist nicht viel anders.Sie können Typklassen verwenden, um dies geschickt zu umgehen:
Jetzt können Sie die Kleinbuchstaben auch für andere Typen verwenden, indem Sie geeignete Instanzen definieren.
quelle