Gibt es eine Chance, "C-Dur" anstelle von "Dur C" zu schreiben?


39

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 Scaleaus a Keyund a konstruieren Mode. Das Modeunterscheidet zB eine Dur- und eine Moll-Tonleiter.

Ich kann den ModeTyp als Funktion von Keybis 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 Keyeine Funktion erstellen, die a Scaleaus 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 Keyauch eine Instanz von sein Show.


Ich kann das Modenach dem setzen, Keywenn 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 scalenicht wirklich mit Skalen. Der intelligente Teil ist in major, scaleist wirklich gerecht flip ($).


Die Verwendung von a newtype Mode = Major | Minor ...ändert sich nicht wirklich, außer scaledass es intelligenter sein muss:

aScale = scale C Major

3
Ich selbst habe in der Vergangenheit eine extrem ähnliche Syntax gesucht, aber TBH ist es nicht wert. Geh einfach mit major C.
Links um den

4
Genau wie ein musikalischer Streitpunkt: „Key“ ist ein irreführender Name für diesen Datentyp, da z. B. C-Dur und C-Moll unterschiedliche Tonarten in der Standardterminologie sind. "PitchClass" wäre ein genauerer Name für den Typ.
PLL

2
@PLL In der Tat habe ich Probleme, einen guten Namen für C, C #, D zu finden ... Ich weiß, dass Euterpea PitchClass verwendet. Es ist korrekter als Key, aber überhaupt nicht "musikalisch". Im Moment spiele ich mit der Idee, es Root oder Tonic zu nennen, obwohl dies nur Akkorde und Skalen suggeriert. Wie zum Teufel nennen Musiker das Ding - eine Note ohne Oktave?
Martin Drautzburg

4
@MartinDrautzburg: Ich würde nicht sagen, dass die Tonhöhenklasse nicht musikalisch ist - sie spricht keineswegs nur Programmierer, sie ist in der Musiktheorie seit mindestens der Mitte des 20. Jahrhunderts als „Note ohne Oktave“ etabliert. Es ist nicht sehr häufig außerhalb technischer musiktheoretischer Kontexte, aber das liegt nur daran, dass die genaue Unterscheidung zwischen „einer Tonhöhe“ und „einer Tonhöhe ohne Oktave“ im täglichen Gebrauch nicht oft benötigt wird und wenn es benötigt wird, ist es normalerweise klar aus dem Kontext. Aber "Root" oder "Tonic" klingen gut als etwas bekanntere Begriffe, wenn auch weniger präzise.
PLL

1
Nein, weil es nicht funktioniert, umgekehrt, ein Programmierer, der Musik macht
Emobe

Antworten:


29

Lösung 1:

Benutze das

data Mode  = Major | Minor
data Scale = C Mode | D Mode | E Mode | F Mode | G Mode | A Mode | B Mode 

Jetzt können Sie schreiben (mit Großbuchstaben C und Großbuchstaben M)

aScale = C Major

Lösung 2a:

Dies ist auch möglich

data Mode  = Major | Minor
data Key   = C | D | E | F | G | A | B 

data Scale = Scale Key Mode  

Jetzt schreibst du

aScale = Scale C Major

Lösung 2b:

Dies ist auch möglich

data Mode  = Major | Minor
data Key   = C | D | E | F | G | A | B 

type Scale = (Key, Mode)  

Jetzt schreibst du

aScale = (C, Major)

IMO mit Lösung 2 wird Ihnen gute Dienste leisten. Geben Sie sich der Syntax von haskell hin und machen Sie daraus ein sauberes Modell Ihrer Domain. Dinge können angenehm sein, wenn Sie tun
luqui

16

Hier ist eine skurrile Lösung, die ich nicht wirklich empfehle, die aber sehr "musikalisch" aussieht:

infix 8 
(♮) :: Key -> Mode -> Scale
(♮) = (Data.Function.&)
 -- ≡ flip ($)

Dann kannst du schreiben

> C major :: Scale

Natürlich, wo dies wirklich angestrebt wird, ist, dass Sie auch haben F♯ minorund B♭ majoretc ..


1
Ich frage mich, ob es so etwas wie
ununterbrochenen

26
@chepner eigentlich ja: 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.
Links um den

11

Wenn Ihnen ein zusätzlicher Operator nichts ausmacht, können Sie &von verwenden Data.Function. Angenommen, dies majorist eine Funktion Key -> Scale, könnten Sie schreiben C & major. Das ergibt einen ScaleWert:

Prelude Data.Function> :t C & major
C & major :: Scale

4

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:

data Mode = Major | Minor                 deriving (Show)
data Key = C | D | E | F | G | A | B      deriving (Show)
data Semitone = Flat | Natural | Sharp    deriving (Show)

data Note = Note Key Semitone             deriving (Show)
data Scale = Scale Note Mode              deriving (Show)
data Chord = Chord [Note]                 deriving (Show)

Sie können einen Continuation-Passing-Typ einführen:

type Cont a r = (a -> r) -> r

und schreiben Sie die primitiven Notizenbildungstypen, um ContTypen wie diese zu erstellen :

a, b, c :: Cont Note r
a = mkNote A
b = mkNote B
c = mkNote C
-- etc.
mkNote a f = f $ Note a Natural

flat, natural, sharp :: Note -> Cont Note r
flat    = mkSemi Flat
natural = mkSemi Natural
sharp   = mkSemi Sharp
mkSemi semi (Note k _) f = f $ Note k semi

Dann können die Funktionen zum Erstellen von Skalen, Noten und Akkorden die Conts in einfache Typen in jeder Postfix-Form auflösen (dh als Fortsetzung, die an die übergeben werden soll Cont):

major, minor :: Note -> Scale
major n = Scale n Major
minor n = Scale n Minor

note :: Note -> Note
note = id

oder Präfixform (dh Conts als Argumente nehmen):

chord :: [Cont Note [Note]] -> Chord
chord = Chord . foldr step []
  where step f acc = f (:acc)

Jetzt können Sie schreiben:

> c sharp note
Note C Sharp
> c note
Note C Natural
> c major
Scale (Note C Natural) Major
> b flat note
Note B Flat
> c sharp major
Scale (Note C Sharp) Major
> chord [a sharp, c]
Chord [Note A Sharp,Note C Natural]

Beachten Sie, dass es cselbst keine ShowInstanz gibt, dies aber c notetut.

Mit einer Änderung des NoteTyps könnten Sie leicht doppelte Vorzeichen (z. B. c sharp sharpverschieden von d) usw. unterstützen.


Nett. Ich habe tatsächlich versucht, mein Problem zu lösen, Contaber 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 Funktion flip ($)dann ist, bekomme ich Ihr Muster flip ($) B :: Cont Key r. Mein Original aScale = scale C Majorist nicht viel anders.
Martin Drautzburg

3

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). Auch Key sollte eine Instanz von Show sein.

Sie können Typklassen verwenden, um dies geschickt zu umgehen:

{-# LANGUAGE FlexibleInstances #-}

data Key = C | D | E | F | G | A | B deriving(Show)

data Mode = Major | Minor

data Scale = Scale Key Mode

class UsesKey t where
  c, d, e, f, g, a, b :: t

instance UsesKey Key where
  c = C
  d = D
  e = E
  f = F
  g = G
  a = A
  b = B

instance UsesKey (Mode -> Scale) where
  c = Scale C
  d = Scale D
  e = Scale E
  f = Scale F
  g = Scale G
  a = Scale A
  b = Scale B

aScale :: Scale
aScale = c Major

Jetzt können Sie die Kleinbuchstaben auch für andere Typen verwenden, indem Sie geeignete Instanzen definieren.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.