“Major C” yerine “C major” yazma şansı var mı?


39

Müzik projemde küçük bir estetik sorunla karşılaştım ve bir süredir beni rahatsız ediyor.

Bir tipim var data Key = C | D | ...ve Scalea Keyve a ' dan a oluşturabilirim Mode. ModeBüyük ve küçük ölçekli örneğin arasındaki farklılaşacaktır.

I tanımlayabilir Modebir fonksiyonu olarak türü Keyiçin Scale. Bu durumda, modların küçük harfli adları vardır (ki bu iyidir) ve böyle bir Ölçek alabilirim

aScale = major C

Ama müzisyenler böyle konuşmuyor. Bu ölçeğe büyük C ölçeği değil, C büyük ölçeği denir.

İstediğim

İdeal olarak yazmak istiyorum

aScale = C major

Bu hiç mümkün mü?

Ne denedim

Ben yapabilir Keybir oluşturur bir işlev Scale, bir gelen Modeyazabilirim böylece,

aScale = c Major

Ama Keys'i Ölçekler oluşturmakla sınırlayamıyorum. Başka şeyler için de gereklidirler (örneğin, akorlar inşa etmek ). Ayrıca Keybir örneği olmalıdır Show.


Ben ekstra bir işlev (veya değer yapıcı) kullandığınızda Modesonra koyabilirsiniz Key:

aScale = scale C major ile scale :: Key -> Mode -> Scale

Ancak ekstra kelime ölçeği gürültülü görünüyor ve isminin aksine, scalegerçekten ölçeklerle ilgilenmiyor. Akıllı parçası olduğunu major, scalegerçekten sadece bir flip ($).


A'nın kullanılması newtype Mode = Major | Minor ...gerçekten daha fazla değişmez, ancak scaledaha akıllı olması gerekir:

aScale = scale C Major

3
Kendimi geçmişte son derece benzer bir sözdizimi isterken buldum, ama TBH buna değmez. Sadece git major C.
leftaroundabout

4
Müzikal bir kelime oyunu gibi: “Anahtar” bu veri tipi için yanıltıcı bir isimdir, çünkü örneğin C major ve C minor, standart terminlojide farklı anahtarlardır. “PitchClass”, tür için daha doğru bir ad olacaktır.
PLL

2
@PLL Gerçekten de, C, C #, D için iyi bir isim bulmakta sorun yaşıyorum ... Euterpea'nın PitchClass kullandığını biliyorum. Key'den daha doğrudur, ama “müzikal” değildir. Şu anda sadece Akorlar ve Teraziler önermekle birlikte Kök veya Tonik olarak adlandırıyorum. Müzisyenler buna ne diyor - Oktavsız bir Not?
Martin Drautzburg

4
@MartinDrautzburg: Saha dersinin müzikal olmadığını söyleyemem - sadece hiçbir şekilde programcı-konuşmakla kalmaz, en azından 20. yüzyılın ortalarından bu yana müzik teorisinde “oktavsız bir not” anlamına gelir. Teknik müzik teorisi bağlamlarının çok dışında değildir, ancak bunun nedeni, günlük kullanımda gerçekten “perde” ve “oktavsız perde” arasındaki kesin ayrımın gerçekten gerekli olmaması ve gerektiğinde genellikle açık olmasıdır. bağlamdan. Ancak "Kök" veya "Tonik", daha az hassassa, biraz daha tanıdık terimler olarak iyi görünür.
PLL

1
Hayır, çünkü tam tersi çalışmıyor, bir programcı müziğe gidiyor
Emobe

Yanıtlar:


29

Çözüm 1:

Bunu kullan

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

Şimdi yazabilirsiniz (büyük C ve büyük M ile)

aScale = C Major

Çözüm 2a:

Bu da mümkün

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

data Scale = Scale Key Mode  

Şimdi yaz

aScale = Scale C Major

Çözüm 2b:

Bu da mümkün

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

type Scale = (Key, Mode)  

Şimdi yaz

aScale = (C, Major)

Çözüm 2 ile devam eden IMO size iyi hizmet edecektir. Haskell'in sözdizimine teslim olun ve alan adınızın temiz bir modelini yapın.
Yaparsanız

16

İşte gerçekten tavsiye etmediğim ama çok “müzikal” görünen tuhaf bir çözüm:

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

Sonra yazabilirsin

> C major :: Scale

Bu gerçekten amaçlanmıştır Elbette ki, siz de sahip olması esastır F♯ minorve B♭ majorvb ..


1
Operatör olarak izin verilen kırılmaz alan gibi bir şey var mı acaba :)
chepner

26
@ chepner aslında evet: U + 2800 BRAILLE DESEN BLANK bir infix olarak kullanılabilir. Söylemeye gerek yok, bu korkunç bir fikir ... Tüm gerçek uzay karakterleri infix olarak yasaklandı, ancak şaşırtıcı olmayan bir şekilde Unicode, kötüye kullanım amacına hacklenebilecek bir şey içeriyor.
leftaroundabout

11

Eğer fazladan operatörü sakıncası yoksa şunu kullanabilirsiniz &gelen Data.Function. Bunun majorbir işlev olduğunu varsayarak, Key -> Scaleyazabilirsiniz C & major. Bu bir Scaledeğer üretir :

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

4

Zaten birkaç iyi yanıt var, ancak burada yardımcı olabilecek bir devam eden stil çözümü (belki de bu belirli örnek için değil, bir tür ters uygulama sözdiziminin istendiği diğer bağlamlarda).

Bazı sorun alanı türleri için standart tanımlarla:

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)

devam eden bir tür girebilirsiniz:

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

ve aşağıdaki Contgibi türler oluşturmak için ilkel not oluşturma türlerini yazın:

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

Ardından, ölçek, nota ve akor oluşturma işlevleri Conts'yi düzeltme sonrası formlarında (yani, iletime devam edilecek şekilde Cont) düz tiplere çözümleyebilir :

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

note :: Note -> Note
note = id

veya önek formu (yani, Contargüman olarak almak):

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

Şimdi yazabilirsiniz:

> 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]

cKendisinin bir Showörneği olmadığını unutmayın c note.

Türde bir değişiklik yaparak, Notekolayca çift kazara (örneğin c sharp sharp, farklı d) vb.


Güzel. Aslında sorunumu çözmeye Contçalıştım, ancak A | B | C ...işlevleri kullanmak yerine yapıcılara yapışmaya çalıştım . Bunu çalıştıramadım ve değer yapıcıların sadece işlevler olduğu göz önüne alındığında, nedenini hala anlamıyorum. Tuşlarımın önüne bir işlev yapıştırabilirsem, birçok şey mümkün olur. Eğer fonksiyon buysa flip ($)ben de kalıbınızı alıyorum flip ($) B :: Cont Key r. Orijinalim aScale = scale C Majorçok farklı değil.
Martin Drautzburg

3

Ama Keys'i Ölçekler oluşturmakla sınırlayamıyorum. Başka şeyler için de gereklidirler (örneğin, akorlar inşa etmek). Ayrıca Anahtar, Show'un bir örneği olmalıdır.

Akıllıca bu sorunu çözmek için tipik sınıfları kullanabilirsiniz:

{-# 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

Artık uygun örnekleri tanımlayarak diğer türler için küçük harfleri de kullanabilirsiniz.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.