Apakah ada kesempatan untuk menulis "C mayor" daripada "mayor C"?

39

Saya mengalami masalah estetika kecil dalam proyek musik saya dan itu telah mengganggu saya selama beberapa waktu.

Saya memiliki tipe data Key = C | D | ...dan saya dapat membangun Scaledari Keydan Mode. Yang Modemembedakan antara skala mayor dan minor.

Saya dapat mendefinisikan Modetipe sebagai fungsi dari Keyhingga Scale. Dalam hal ini mode akan memiliki nama huruf kecil (yang baik-baik saja) dan saya bisa mendapatkan Skala seperti ini

aScale = major C

Tetapi musisi tidak berbicara seperti ini. Mereka menyebut skala ini sebagai skala C mayor , bukan skala C mayor .

Apa yang saya inginkan

Idealnya saya ingin menulis

aScale = C major

Apakah ini mungkin?

Apa yang saya coba

Saya dapat membuat Keyfungsi yang membangun a Scaledari Mode, jadi saya bisa menulis

aScale = c Major

Tapi saya tidak bisa membatasi Kunci untuk membangun Timbangan. Mereka diperlukan untuk hal-hal lain juga (misalnya membangun akord ). Juga Keyharus menjadi contoh dari Show.


Saya bisa meletakkan Modesetelah Keyketika saya menggunakan fungsi tambahan (atau konstruktor nilai):

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

Tetapi skala kata tambahan terlihat berisik dan bertentangan dengan namanya, scaletidak terlalu peduli dengan skala. Bagian yang cerdas adalah major, scalebenar-benar adil flip ($).


Menggunakan a newtype Mode = Major | Minor ...tidak terlalu banyak berubah, kecuali scaleharus lebih pintar:

aScale = scale C Major
Martin Drautzburg
sumber
3
Saya sendiri mendapati diri saya menginginkan sintaks yang sangat mirip di masa lalu, tetapi TBH tidak sepadan. Ikuti saja major C.
leftaroundtentang
4
Sama seperti berdalih musik: "Kunci" adalah nama yang menyesatkan untuk tipe data itu, karena misalnya C mayor dan C minor adalah kunci yang berbeda dalam terminologi standar. "PitchClass" akan menjadi nama yang lebih akurat untuk jenisnya.
PLL
2
@ PLL Memang, saya kesulitan menemukan nama yang baik untuk C, C #, D ... Saya tahu Euterpea menggunakan PitchClass. Itu lebih benar daripada Key, tetapi sama sekali bukan "musikal". Saat ini saya bermain dengan ide menyebutnya Root atau Tonic meskipun itu hanya menyarankan Chords dan Scales. Apa yang para musisi sebut sebagai benda - Catatan tanpa Oktaf?
Martin Drautzburg
4
@MartinDrautzburg: Saya tidak akan mengatakan bahwa kelas pitch adalah non-musikal - ini bukan hanya bahasa pemrograman dengan cara apa pun, itu telah ditetapkan dalam teori musik yang berarti “nada tanpa oktaf” sejak setidaknya sekitar pertengahan abad ke-20. Ini tidak terlalu umum di luar konteks teori musik teknis, tapi itu hanya karena perbedaan yang tepat antara "nada" dan "nada tanpa oktaf" tidak benar-benar sering dibutuhkan dalam penggunaan sehari-hari, dan ketika dibutuhkan, biasanya jelas dari konteks. Tapi "Root" atau "Tonic" terdengar bagus sebagai istilah yang sedikit lebih akrab, jika kurang tepat.
PLL
1
Tidak karena itu tidak bekerja sebaliknya, seorang programmer masuk ke musik
Emobe

Jawaban:

29

Solusi 1:

Gunakan ini

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

Sekarang Anda bisa menulis (dengan modal C dan modal M)

aScale = C Major

Solusi 2a:

Ini juga mungkin

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

data Scale = Scale Key Mode  

Sekarang kamu menulis

aScale = Scale C Major

Solusi 2b:

Ini juga mungkin

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

type Scale = (Key, Mode)  

Sekarang kamu menulis

aScale = (C, Major)
Elmex80s
sumber
IMO dengan solusi 2 akan melayani Anda dengan baik. Menyerahkan diri ke sintaks haskell dan menjadikannya model domain Anda yang bersih. Hal-hal dapat menjadi menyenangkan jika Anda melakukannya
luqui
16

Inilah salah satu solusi aneh yang tidak saya rekomendasikan, tetapi terlihat sangat "musikal":

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

Maka Anda bisa menulis

> C major :: Scale

Tentu saja, di mana ini benar-benar ditujukan adalah bahwa Anda juga akan memiliki F♯ minordan B♭ majorlain - lain.

leftaroundabout
sumber
1
Saya ingin tahu apakah ada sesuatu seperti ruang bebas-
gangguan
26
@ chepner sebenarnya ya: U + 2800 POLA BRAILLE BLANK dapat digunakan sebagai infiks. Tak perlu dikatakan, ini adalah ide yang mengerikan ... Semua karakter ruang yang sebenarnya dilarang sebagai infiks, tetapi tidak mengejutkan Unicode berisi sesuatu yang dapat diretas ke dalam tujuan penyalahgunaan.
leftaroundabout
11

Jika Anda tidak keberatan dengan operator tambahan, Anda dapat menggunakan &dari Data.Function. Dengan asumsi itu majoradalah fungsi Key -> Scale, Anda bisa menulis C & major. Itu menghasilkan Scalenilai:

Prelude Data.Function> :t C & major
C & major :: Scale
Mark Seemann
sumber
4

Sudah ada beberapa jawaban yang baik, tetapi inilah solusi gaya kelanjutan lewat yang mungkin membantu (mungkin bukan untuk contoh khusus ini, tetapi dalam konteks lain di mana semacam sintaks aplikasi balik diinginkan).

Dengan definisi standar untuk beberapa jenis domain masalah:

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)

Anda dapat memperkenalkan jenis kelanjutan-lewat:

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

dan tulis tipe-tipe primitif untuk membangun Conttipe-tipe seperti:

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

Kemudian, fungsi pembangunan skala, note, dan chord dapat menyelesaikan Conts ke tipe plain dalam bentuk postfix (yaitu, sebagai kelanjutan yang akan diteruskan ke Cont):

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

note :: Note -> Note
note = id

atau bentuk awalan (yaitu, mengambil Conts sebagai argumen):

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

Sekarang, Anda dapat menulis:

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

Perhatikan bahwa citu sendiri tidak memiliki Showinstance, tetapi c notetidak.

Dengan modifikasi pada Notejenisnya, Anda dapat dengan mudah mendukung kecelakaan ganda (mis. c sharp sharp, Berbeda dari d), dll.

KA Buhr
sumber
Bagus. Saya benar-benar mencoba untuk menyelesaikan masalah saya dengan Contbagaimanapun, saya mencoba untuk tetap menggunakan konstruktor A | B | C ...daripada menggunakan fungsi. Saya tidak bisa mendapatkan ini untuk bekerja dan saya masih tidak mengerti mengapa, mengingat bahwa konstruktor nilai hanyalah fungsi. Jika saya dapat menempelkan fungsi di depan Kunci saya, banyak hal menjadi mungkin. Jika fungsinya flip ($)maka saya mendapatkan polanya flip ($) B :: Cont Key r. Dokumen asli saya aScale = scale C Majortidak jauh berbeda.
Martin Drautzburg
3

Tapi saya tidak bisa membatasi Kunci untuk membangun Timbangan. Mereka diperlukan untuk hal-hal lain juga (misalnya membangun akord). Juga Key harus merupakan instance dari Show.

Anda dapat menggunakan kacamata ketik untuk secara cerdik mengatasinya:

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

Sekarang, Anda juga dapat menggunakan huruf kecil untuk jenis lain dengan mendefinisikan instance yang sesuai.

Joseph Sible-Reinstate Monica
sumber