Eu encontrei um pequeno problema estético no meu projeto musical e ele está me incomodando há algum tempo.
Eu tenho um tipo data Key = C | D | ...
e posso construir a Scale
partir de a Key
e a Mode
. Os Mode
distingue entre, por exemplo, um grande e um menor escala.
Eu posso definir o Mode
tipo como uma função de Key
para Scale
. Nesse caso, os modos terão nomes em minúsculas (o que é bom) e posso obter uma escala como esta
aScale = major C
Mas músicos não falam assim. Eles se referem a essa escala como a escala C maior , não a escala C maior.
O que eu quero
Idealmente, eu gostaria de escrever
aScale = C major
Isso é possível em tudo?
O que eu tentei
Eu posso criar Key
uma função que construa a Scale
de a Mode
, para que eu possa escrever
aScale = c Major
Mas não posso limitar as chaves à construção de escalas. Eles são necessários para outras coisas também (por exemplo, construção de acordes ). Também Key
deve ser uma instância de Show
.
Eu posso colocar o Mode
depois do Key
quando eu uso uma função extra (ou construtor de valor):
aScale = scale C major
com scale :: Key -> Mode -> Scale
Mas a escala extra de palavras parece barulhenta e, ao contrário do nome, scale
não está realmente preocupada com escalas. A parte inteligente está dentro major
, scale
é realmente justa flip ($)
.
Usar um newtype Mode = Major | Minor ...
realmente não muda muito, exceto que scale
precisa ser mais inteligente:
aScale = scale C Major
major C
.Respostas:
Solução 1:
Usa isto
Agora você pode escrever (com maiúsculas C e maiúsculas M)
Solução 2a:
Isso também é possível
Agora você escreve
Solução 2b:
Isso também é possível
Agora você escreve
fonte
Aqui está uma solução extravagante que eu realmente não recomendo, mas parece muito "musical":
Então você pode escrever
Claro, onde isso é realmente direcionado é que você também teria
F♯ minor
eB♭ major
etc.fonte
⠀
U + 2800 BRAILLE PATTERN BLANK pode ser usado como um infix. Escusado será dizer que esta é uma idéia horrível ... Todos os caracteres espaciais reais são proibidos como infixos, mas, sem surpresa, o Unicode contém algo que pode ser invadido por motivos de abuso.Se você não se importa com um operador extra, pode usar a
&
partir deData.Function
. Supondo quemajor
seja uma funçãoKey -> Scale
, você poderia escreverC & major
. Isso produz umScale
valor:fonte
Já existem várias respostas boas, mas aqui está uma solução de estilo de passagem contínua que pode ser útil (talvez não para este exemplo específico, mas em outros contextos em que é necessária uma espécie de sintaxe de aplicativo reverso).
Com definições padrão para alguns tipos de domínio com problemas:
você pode introduzir um tipo de passagem de continuação:
e escreva os tipos primitivos de criação de notas para criar
Cont
tipos assim:Em seguida, as funções de escala, nota e construção de acordes podem resolver os
Cont
tipos simples de s em qualquer forma de postfix (ou seja, como continuações a serem passadas para oCont
):ou forma de prefixo (ou seja, usando
Cont
s como argumentos):Agora, você pode escrever:
Observe que
c
ele próprio não possui umaShow
instância, masc note
possui.Com uma modificação no
Note
tipo, você pode facilmente suportar acidentes duplos (por exemploc sharp sharp
, distintos ded
), etc.fonte
Cont
entanto, tentei atendê-lo aos construtores emA | B | C ...
vez de usar funções. Eu não consegui fazer isso funcionar e ainda não entendo o porquê, dado que os construtores de valor são apenas funções. Se eu conseguir colocar uma função na frente das minhas teclas, muitas coisas se tornam possíveis. Se a função forflip ($)
, entendo seu padrãoflip ($) B :: Cont Key r
. Meu originalaScale = scale C Major
não é muito diferente.Você pode usar classes tipográficas para solucionar isso de maneira inteligente:
Agora, você também pode usar as letras minúsculas para outros tipos, definindo instâncias apropriadas.
fonte