「メジャーC」ではなく「Cメジャー」と書く機会はありますか?


39

音楽プロジェクトで小さな美的問題に遭遇し、しばらくの間悩まされてきました。

タイプがdata Key = C | D | ...ありScale、a Keyとa からを構築できModeます。Mode例えば、Aメジャーとマイナースケールを区別します。

Modeタイプを関数Keyto からとして定義できますScale。その場合、モードには小文字の名前が付き(これで問題ありません)、次のようなスケールを取得できます。

aScale = major C

しかし、ミュージシャンはこのように話しません。彼らはこのスケールをメジャーCスケールではなく、Cメジャースケールと呼びます。

私が欲しいもの

理想的には書きたい

aScale = C major

これはまったく可能ですか?

私が試したもの

からa Keyを作成する関数を作成できるので、ScaleMode

aScale = c Major

しかし、キーをスケールの構築に限定することはできません。それらは他のものにも必要です(例えば、コードの構築)。またKey、のインスタンスである必要がありますShow


追加の関数(または値コンストラクター)を使用する場合、Modeその後に置くことができKeyます。

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

しかし、余分な単語スケールは、その名前に反して騒々しく見え、scale実際にはスケールとは関係ありません。インテリジェントな部分はにありmajorscale本当にただflip ($)です。


よりインテリジェントである必要があることnewtype Mode = Major | Minor ...を除いて、aを使用してもそれほど大きな変化はありませんscale

aScale = scale C Major

3
私は自分が過去に非常に似た構文を望んでいることに気づきましたが、TBHはそれだけの価値はありません。だけで行くmajor C
leftaroundabout

4
音楽の難しさのように:「キー」は、そのデータ型の誤解を招く名前です。たとえば、CメジャーとCマイナーは、標準的な用語では異なるキーです。「PitchClass」は、タイプのより正確な名前になります。
PLL

2
@PLL確かに、C、C#、Dの適切な名前を見つけるのに苦労しています... EuterpeaがPitchClassを使用していることは知っています。キーよりも正しいですが、「ミュージカル」ではありません。現在、私はそれをルートまたはトニックと呼ぶという考えで遊んでいますが、それはコードとスケールのみを示唆しています。ミュージシャンはそれを一体何と呼びますか-オクターブのないノート?
マーティンドラウツブルク

4
@MartinDrautzburg:ピッチクラスは音楽的ではないとは言えません。これは、決してプログラマーが話すだけではなく、少なくとも20世紀半ば頃から「オクターブのない音符」を意味するものとして音楽理論で確立されました。それは、技術的な音楽理論の文脈の外ではあまり一般的ではありませんが、それは、「ピッチ」と「オクターブのないピッチ」の正確な区別が、日常の使用ではあまり必要とされないことが多いためです。コンテキストから。しかし、「Root」または「Tonic」は、あまり正確ではないにせよ、もう少し慣れ親しんだ用語としてうまく聞こえます。
PLL

1
いいえ、その逆では機能しないため、プログラマーが音楽に
取り掛かります

回答:


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はうまく機能します。haskellの構文に降伏し、その中にドメインのクリーンなモデルを作成します。あなたがするなら物事は楽しいことができます
ルキ

16

これは私があまりお勧めしない奇抜な解決策ですが、非常に「音楽的」に見えます。

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

その後、あなたは書くことができます

> C major :: Scale

もちろん、これが本当に目的としているのは、あなたが持っているF♯ minorであろうことB♭ majorなどです。


1
オペレーターとして許可されている非分割スペースのようなものがあるのだろうか:)
chepner

26
@chepnerは実際にはい:U + 2800 ブレイレパターンブランクをインフィックスとして使用できます。言うまでもありませんが、これは恐ろしい考えです...実際のすべてのスペース文字はインフィックスとして禁止されていますが、当然のことながらUnicodeには乱用目的にハッキングされる可能性があるものが含まれています。
leftaroundabout

11

余分な演算子を気にしなければ、&fromを使用できます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は大した違いはありません。
マーティンドラウツブルク

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.