问题描述
我在演奏音符名称的目的是不混淆同音等号,即我想正确处理临时记号(升号和降号)。即使 B
和 Fs
是钢琴键盘上的同一个键,Gb
上方的完美五分之一的音符必须是 Fs
而不是 Gb
.
此外,我还希望能够方便地编写 e.e. Fs
在 haskell 程序中,没有空格、引号或额外的函数@H_502_16@。
我最终定义了 35 个构造函数,范围从 Cbb
到 Bss
。虽然这行得通并且确实得到了临时记号,但我对最多两个临时记号的限制感到不满。在内部,我们无论如何都表示为Int
。
- 有没有办法定义无限数量的构造函数,如标题中所示,因此可以使用任意数量的记号(如
Cbbbb
)?也许是模板haskell? - 或者,我是否可以方便地在 Haskell 程序中编写
Cbbbb
(没有引号、空格或额外的函数@H_502_16@),而无需将Cbbbb
设为构造函数?
解决方法
我同意 Carsten 的观点,即实际上拥有大量这样的分散构造函数是一个坏主意。使用像
这样的数据更明智data BaseNote = C | D | E | F | G | A | B
data PitchClass = PitchClass
{ baseNote :: BaseNote,accidentals :: Int }
data Note = Note
{ pitchClass :: PitchClass,octave :: Int }
至于
此外,我还希望能够方便地编写 e.e. Fs
在 haskell 程序中,没有空格、引号或额外的函数。
您有多种选择。
-
您可以使用
-XPatternSynonyms
。这使您可以为已定义的数据类型获得可匹配的构造函数。{-# LANGUAGE PatternSynonyms #-} pattern Cn = PitchClass C 0 pattern Cs = PitchClass C 1 pattern Cb = PitchClass C (-1) ...
这些可以由 TemplateHaskell 宏提供以避免代码重复。
-
您可以提供一个函数,使其看起来像单个构造函数名称一样紧凑,但实际上并非如此。
(♮),(♯),(♭) :: BaseNote -> Int -> Note bn♮octv = Note (PitchClass bn 0) octv bn♯octv = Note (PitchClass bn 1) octv bn♭octv = Note (PitchClass bn (-1)) octv
现在你可以写类似的东西
[A♮2,A♮2,C♯3,D♮3,C♯3]
TBH 我认为这两个都不是很好。 IMO 更有意义的是,根本不以绝对音高来指定音乐素材,而是将其指定为 音阶度 或 间隔步骤 的序列。