Haskell 有没有机会写一封信;C大调“;而不是",;大C";?

Haskell 有没有机会写一封信;C大调“;而不是",;大C";?,haskell,dsl,Haskell,Dsl,我在我的音乐项目中遇到了一个小的美学问题,它困扰了我一段时间 我有一个类型data Key=C | D |…,我可以从键和模式构建比例。模式区分大音阶和小音阶等 我可以将模式类型定义为从键到缩放的函数。在这种情况下,模式将使用小写名称(这很好),我可以得到这样的比例 aScale = major C 但音乐家不会这样说话。他们把这个音阶称为C大调音阶,而不是C大调音阶 我想要什么 理想情况下,我会想写作 aScale = C major 这可能吗 我尝试的 我可以使键成为一个函数,从模式构造

我在我的音乐项目中遇到了一个小的美学问题,它困扰了我一段时间

我有一个类型
data Key=C | D |…
,我可以从
键和
模式构建
比例。
模式
区分大音阶和小音阶等

我可以将
模式
类型定义为从
缩放
的函数。在这种情况下,模式将使用小写名称(这很好),我可以得到这样的比例

aScale = major C
但音乐家不会这样说话。他们把这个音阶称为C大调音阶,而不是C大调音阶

我想要什么

理想情况下,我会想写作

aScale = C major
这可能吗

我尝试的

我可以使
成为一个函数,从
模式
构造一个
刻度
,这样我就可以写了

aScale = c Major
> C♮ major :: Scale
但我不能将关键点局限于构建比例。其他事情也需要它们(例如构造和弦)。另外,
Key
应该是
Show
的一个实例


使用额外函数(或值构造函数)时,我可以将
模式
置于
之后:

aScale=C大调音阶
scale::Key->Mode->scale

但是额外的单词scale看起来很嘈杂,与它的名字相反,
scale
与scale并不真正相关。智能部分在
大调
刻度
实际上就是
翻转($)


使用
newtype Mode=Major | Minor…
实际上变化不大,除了
scale
需要更智能:

aScale = scale C Major

解决方案1:

用这个

data Mode  = Major | Minor
data Scale = C Mode | D Mode | E Mode | F Mode | G Mode | A Mode | B Mode 
现在你可以写了(大写C和M)

解决方案2a:

这也是可能的

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

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

type Scale = (Key, Mode)  
现在你写

aScale = Scale C Major
aScale = (C, Major)
解决方案2b:

这也是可能的

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

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

type Scale = (Key, Mode)  
现在你写

aScale = Scale C Major
aScale = (C, Major)

如果您不介意增加一个运算符,您可以使用
Data.Function
中的
&
。假设
major
是一个函数
Key->Scale
,您可以编写
C&major
。产生
比例
值的:

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

这里有一个我并不推荐但看起来很“音乐化”的异想天开的解决方案:

infix 8 ♮
(♮) :: Key -> Mode -> Scale
(♮) = (Data.Function.&)
 -- ≡ flip ($)
然后你就可以写了

aScale = c Major
> C♮ major :: Scale

当然,这真正的目的是你也会有
F♯ 次要
B♭ major
等..

已经有好几个好的答案,但是这里有一个延续传递样式的解决方案可能会有所帮助(可能不是针对这个特定的示例,而是在需要某种反向应用程序语法的其他上下文中)

使用某些问题域类型的标准定义:

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
然后,音阶、音符和和弦构建函数可以将
Cont
解析为任意后缀形式的普通类型(即作为要传递给
Cont
的延续):

或前缀形式(即,将
Cont
s作为参数):

现在,你可以写:

> 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

通过修改
注释
类型,您可以轻松支持双重意外(例如,
c sharp
,与
d
不同),等等

但我不能将关键点局限于构建比例。其他事情也需要它们(例如构造和弦)。键还应该是Show的一个实例

您可以使用TypeClass巧妙地解决这一问题:

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

现在,通过定义适当的实例,您也可以将小写字母用于其他类型。

我发现自己在过去需要非常相似的语法,但这并不值得。只需使用
大调C
。就像音乐中的一句俏皮话:“Key”是该数据类型的一个误导性名称,因为例如C大调和C小调在标准术语中是不同的键。“PitchClass”将是该类型更准确的名称。@事实上,我很难找到C、C#、D的好名称。。。我知道Euterpea使用PitchClass。它比基调更正确,但根本不是“音乐”。现在我想把它叫做根音或主音,虽然这只意味着和弦和音阶。音乐家们管那玩意儿叫什么?没有八度的音符?@MartinDrautzburg:我不会说音高课没有音乐性——它不只是程序员用任何方式说话,它在音乐理论中被确定为“没有八度的音符”的意思,至少在20世纪中叶左右。这在技术音乐理论背景之外并不常见,但这只是因为“一个音高”和“一个没有八度的音高”之间的精确区别在日常使用中并不经常需要,而且当需要时,通常可以从背景中清楚地看到。但“根”或“主音”听起来更为熟悉,但不够精确。不,因为它不起作用,反之亦然,一个进入musicI的程序员想知道是否有像不间断空格这样的东西可以作为操作符:)@chepner实际上是:
U+2800盲文模式空白可以用作中缀。不用说,这是一个可怕的想法。。。所有实际的空格字符都被禁止作为中缀,但不出所料,Unicode包含一些可以被入侵的东西。实际上,我确实试图用
Cont
来解决我的问题,但是,我试图将它坚持到构造函数
A | B | C…
上,而不是使用函数。我不能让它工作,我仍然不明白为什么,因为值构造函数只是函数。如果我能在我的按键前粘贴一个函数,许多