有没有可能写成"C大调"而不是"C大调"?
我在我的音乐项目中遇到了一个小的审美问题,它已经困扰了我一段时间了。
我有一个类型data Key = C | D | ...
,我可以从Key
和Mode
构建一个Scale
。模式 "可以区分大调和小调音阶。
我可以将 "模式 "类型定义为一个从 "键 "到 "音阶 "的函数。在这种情况下,模式将有小写的名字(这很好),我可以得到一个像这样的音阶
aScale = major C
但音乐家们不会这样说话。他们把这个音阶称为_C大调_音阶,而不是_C大调_音阶。
我想的是
理想情况下,我想写的是
aScale = C major
这到底有没有可能?
我所尝试的
我可以让Key
成为一个函数,从Mode
构建一个Scale
,所以我可以写出
aScale = c Major
但我不能把钥匙局限于构造音阶。其他事情也需要它们(例如构造和弦)。另外,"键 "应该是 "显示 "的一个实例。
当我使用一个额外的函数(或值构造器)时,我可以把Mode
放在Key
后面:
aScale = scale C major
与scale ::Key -> Mode -> Scale
。
但额外的词scale看起来很吵,与它的名字相反,scale
并不真正关心音阶。聪明的部分是在大调
中,音阶
实际上只是翻转($)
。
使用newtype Mode = Major | Minor ...除了
scale'需要更智能外,并没有什么变化:
aScale = scale C Major
32
5
解决方案1:
使用这个
现在你可以写(大写C和大写M)了
解决方案2a:
这也是可能的
现在你写
解决方案2b:
这也是可能的
现在你写
这里有一个异想天开的解决方案,我不太推荐,但看起来很有 "音乐感":
然后你可以写
当然,这真正的目的是,你也会有
F♯小调
和降B大调
等等。如果你不介意多一个运算符,你可以使用
Data.Function
中的&
。假设major'是一个
Key -> Scale'的函数,你可以写C & major'。这将产生一个
音阶'值:已经有好几个好的答案了,但这里有一个延续传递风格的解决方案,可能会有帮助(也许不适合这个特殊的例子,但在其他想要某种反向应用语法的情况下)。
用一些问题域类型的标准定义。
你可以引入一个延续传递类型。
并写出原始的笔记构建类型来构建
Cont
类型,就像这样。然后,音阶、音符和和弦构建函数可以将
Cont
s解析为后缀形式的纯类型(即作为连续型传递给Cont
)。或前缀形式(即以
Cont
s作为参数)。现在,你可以写了。
请注意,"c "本身没有 "显示 "实例,但 "c note "有。
通过修改
Note
类型,你可以很容易地支持双意外符(例如,c sharp sharp
,与d
不同),等等。你可以使用类型类来巧妙地解决这个问题。
现在,你也可以通过定义适当的实例将小写字母用于其他类型。