"major C"대신 "C major"를 쓸 기회가 있습니까?


39

음악 프로젝트에서 약간의 미적 문제가 발생하여 한동안 버그가 발생했습니다.

나는 타입을 가지고 있으며 a 와 a를 data Key = C | D | ...구성 할 수 있습니다 . 주요 및 사소한 규모를 예 구분합니다.ScaleKeyModeMode

나는 정의 할 수 있습니다 Mode에서 함수 등의 형태 Key로를 Scale. 이 경우 모드는 소문자 이름을 가지며 (괜찮음) 다음과 같이 Scale을 얻을 수 있습니다

aScale = major C

그러나 음악가들은 이렇게 말하지 않습니다. 그들은이 척도를 주요 C 척도가 아닌 C 주요 척도로 지칭합니다 .

내가 원하는 것

이상적으로 쓰고 싶습니다

aScale = C major

이것이 가능합니까?

내가 시도한 것

from Key을 구성하는 함수를 만들 수 있으므로 쓸 수 있습니다.ScaleMode

aScale = c Major

그러나 키를 스케일 생성에 국한시킬 수는 없습니다. 다른 것들도 필요합니다 (예 : 화음 구성 ). 또한 Key의 인스턴스 여야합니다 Show.


추가 함수 (또는 값 생성자)를 사용할 때 Mode이후 를 넣을 수 있습니다 Key.

aScale = scale C majorscale :: Key -> Mode -> Scale

그러나 여분의 단어 스케일 은 시끄럽고 그 이름과 반대로 보이지만 scale실제로 스케일과 관련이 없습니다. 지능형 부분에 major, scale정말입니다 flip ($).


A는 사용 newtype Mode = Major | Minor ...을 제외하고 정말 많이 변경되지 않습니다 scale요구하는 것은 더 지능이 될 수 있습니다 :

aScale = scale C Major

3
나는 과거에 매우 유사한 구문을 원한다는 것을 스스로 발견했지만 TBH는 그만한 가치가 없습니다. 그냥 가십시오 major C.
왼쪽

4
음악적 퀴즈와 마찬가지로“Key”는 해당 데이터 유형에 대한 잘못된 이름입니다. 예를 들어 C 메이저와 C 마이너는 표준 용어에서 다른 키이기 때문입니다. "PitchClass"는 유형에 대한보다 정확한 이름입니다.
PLL

2
@PLL 사실, C, C #, D의 좋은 이름을 찾는 데 어려움을 겪고 있습니다 ... Euterpea가 PitchClass를 사용한다는 것을 알고 있습니다. 키보다 정확하지만 "뮤지컬"은 아닙니다. 지금은 코드 또는 스케일 만 제안하지만 루트 또는 토닉이라고하는 아이디어로 연주하고 있습니다. 도대체 음악가들은 이것을 옥타브가없는 음이라고 부릅니다.
Martin Drautzburg

4
@MartinDrautzburg : 음높이 클래스가 음악적이지 않다고 말하지는 않습니다. 어떤 방식 으로든 프로그래머가 말하는 것이 아니라 음악 이론에서 적어도 20 세기 중반부터 "옥타브가없는 음표"를 의미하는 것으로 확립되었습니다. 일반적으로 기술적 인 음악 이론적 맥락을 벗어난 것은 아니지만 "피치"와 "옥타브없는 피치"의 정확한 구분이 일상적인 사용에서 실제로는 자주 필요하지 않기 때문에 필요한 경우 일반적으로 명확합니다. 문맥에서. 그러나 "루트"또는 "토닉"은 덜 정확한 경우 약간 더 친숙한 용어로 들립니다.
PLL

1
그렇지 않습니다. 그 반대의 경우도 마찬가지입니다. 프로그래머가 음악을 듣습니다
Emobe

답변:


29

해결책 1 :

이것을 사용하십시오

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

이제 대문자 C와 대문자 M을 쓸 수 있습니다.

aScale = C Major

해결책 2a :

이것도 가능합니다

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

data Scale = Scale Key Mode  

이제 당신은 작성

aScale = Scale C Major

해결책 2b :

이것도 가능합니다

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

type Scale = (Key, Mode)  

이제 당신은 작성

aScale = (C, Major)

솔루션 2와 함께하는 IMO가 잘 제공됩니다. 하스켈의 구문을 항복하여 도메인의 깔끔한 모델로 만드십시오. 당신이한다면 일이 즐거워 질 수 있습니다
luqui

16

다음은 실제로 권장하지 않지만 매우 "음악적"인 기발한 솔루션입니다.

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

그럼 당신은 쓸 수 있습니다

> C major :: Scale

이 정말 목표로 물론, 당신도 가질 것입니다 F♯ minorB♭ major


1
비 연속 공간과 같이 운영자로 허용되는 것이 있는지 궁금합니다. :)
chepner

26
@chepner 실제로 예 : U + 2800 BRAILLE PATTERN BLANK는 접두사로 사용할 수 있습니다. 말할 것도없이, 이것은 끔찍한 생각입니다 ... 모든 실제 공간 문자는 접두사로 금지되어 있지만 놀랍게도 유니 코드에는 남용 목적으로 해킹 될 수있는 것이 포함되어 있습니다.
좌회전

11

추가 연산자가 마음에 들지 않으면 &에서 사용할 수 있습니다 Data.Function. 그것이 major함수 라고 가정하면 Key -> Scale쓸 수 C & major있습니다. 그 결과 Scale가치가 있습니다.

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

4

이미 몇 가지 좋은 대답이 있지만 여기에 도움이 될 수있는 연속 전달 스타일 솔루션이 있습니다 (이 특정 예에서는 아니지만 일종의 역 응용 구문이 필요한 다른 상황에서).

일부 문제 도메인 유형에 대한 표준 정의 :

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)

연속 전달 유형을 도입 할 수 있습니다.

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

기본 노트 작성 유형을 작성하여 Cont다음과 같이 유형을 작성하십시오 .

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

그런 다음, 스케일, 음표 및 코드 작성 기능은 Conts를 접두사 형식 (예 Cont: 으로 전달되는 연속)으로 일반 유형으로 해석 할 수 있습니다 .

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

note :: Note -> Note
note = id

또는 접두사 형식 (예 Cont: s를 인수로 사용) :

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

이제 다음과 같이 쓸 수 있습니다 :

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

참고 c자체가없는 Show인스턴스를, 그러나 c note않습니다.

Note유형을 수정하면 이중 실수 (예 : c sharp sharp와 구별됨 d) 등을 쉽게 지원할 수 있습니다 .


좋은. 실제로 문제를 해결 Cont하려고했지만 A | B | C ...함수를 사용하는 대신 생성자에 고정하려고했습니다 . 나는 이것을 작동시킬 수 없었고, 값 생성자가 단지 함수라는 것을 감안할 때 여전히 이유를 이해하지 못한다. 키 앞에 기능을 붙일 수 있다면 많은 것이 가능해집니다. 함수가 flip ($)그렇다면 당신의 패턴을 얻습니다 flip ($) B :: Cont Key r. 내 원본 aScale = scale C Major은 크게 다르지 않습니다.
Martin Drautzburg

3

그러나 키를 스케일 구성에 국한시킬 수는 없습니다. 다른 것들도 필요합니다 (예 : 화음 구성). 또한 Key는 Show의 인스턴스 여야합니다.

타입 클래스를 사용하여 그 문제를 영리하게 해결할 수 있습니다.

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

이제 적절한 인스턴스를 정의하여 다른 유형에도 소문자를 사용할 수 있습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.