我在音乐项目中遇到了一个美学上的小问题,并且困扰了我一段时间。
我具有data Key = C | D | ...
类型,可以从Scale
和Key
构造一个Mode
。 Mode
区分例如主要和次要规模。
我可以将Mode
类型定义为从Key
到Scale
的函数。在这种情况下,模式将使用小写名称(可以),我可以得到一个像这样的Scale
aScale = major C
。
但是音乐家不会这样说话。他们将此标尺称为C major标尺,而不是major C标尺。
我想要什么
理想情况下我想写
aScale = C major
这有可能吗?
我尝试了什么
我可以使Key
成为从Scale
构造Mode
的函数,所以我可以写
aScale = c Major
但是我不能将关键仅限于构建音阶。其他事物也需要它们(例如,构造chords)。另外Key
应该是Show
的实例。
当我使用额外的函数(或值构造函数)时,可以将Mode
放在Key
之后:
[aScale = scale C major
与scale :: Key -> Mode -> Scale
但是多余的单词scale看起来很吵,与它的名字相反,scale
并不真正关心刻度。智能部分在major
中,scale
实际上只是flip ($)
。
使用newtype Mode = Major | Minor ...
并没有多大改变,只是scale
需要更智能:
aScale = scale C Major
[如果您不介意额外的运算符,则可以使用&
中的Data.Function
。假设major
是函数Key -> Scale
,则可以编写C & major
。产生一个Scale
值:
Prelude Data.Function> :t C & major
C & major :: Scale
解决方案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)
这是我不真正推荐的一种异想天开的解决方案,但是看起来很“音乐”:
infix 8 ♮
(♮) :: Key -> Mode -> Scale
(♮) = (Data.Function.&)
-- ≡ flip ($)
然后您可以写
> C♮ major :: Scale
当然,这的真正目的是您还将拥有F♯ minor
和B♭ major
等。