Encontré un pequeño problema estético en mi proyecto de música y me ha estado molestando durante algún tiempo.
Tengo un tipo data Key = C | D | ...
y puedo construir a Scale
de a Key
y a Mode
. El Mode
distingue entre, por ejemplo, una escala mayor y una menor.
Puedo definir el Mode
tipo como una función de Key
a Scale
. En ese caso, los modos tendrán nombres en minúscula (lo cual está bien) y puedo obtener una escala como esta
aScale = major C
Pero los músicos no hablan así. Se refieren a esta escala como la escala C mayor , no la escala C mayor .
Lo que quiero
Idealmente me gustaría escribir
aScale = C major
¿Es esto posible en absoluto?
Lo que probé
Puedo hacer Key
una función que construya a Scale
desde a Mode
, así puedo escribir
aScale = c Major
Pero no puedo limitar Keys a construir escalas. También son necesarios para otras cosas (por ejemplo, construir acordes ). tambiénKey
debería ser una instancia de Show
.
Puedo poner el Mode
después de Key
cuando uso una función adicional (o constructor de valores):
aScale = scale C major
con scale :: Key -> Mode -> Scale
Pero la escala de palabras adicional parece ruidosa y, al contrario de su nombre, scale
no se preocupa realmente por las escalas. La parte inteligente está adentro major
, scale
es realmente justa flip ($)
.
El uso de a newtype Mode = Major | Minor ...
no cambia mucho, excepto que scale
necesita ser más inteligente:
aScale = scale C Major
major C
.Respuestas:
Solución 1:
Utilizar este
Ahora puedes escribir (con C mayúscula y M mayúscula)
Solución 2a:
Esto también es posible
Ahora escribes
Solución 2b:
Esto también es posible
Ahora escribes
fuente
Aquí hay una solución caprichosa que realmente no recomiendo, pero se ve muy "musical":
Entonces puedes escribir
Por supuesto, donde esto realmente está dirigido es que tú también tendrías
F♯ minor
yB♭ major
etc.fuente
⠀
U + 2800 BRAILLE PATTERN BLANK se puede usar como infijo. No hace falta decir que esta es una idea horrible ... Todos los personajes espaciales reales están prohibidos como infijos, pero, como era de esperar, Unicode contiene algo que puede ser pirateado con el propósito de abuso.Si no le importa un operador adicional, puede usarlo
&
desdeData.Function
. Suponiendo quemajor
sea una funciónKey -> Scale
, podrías escribirC & major
. Eso produce unScale
valor:fuente
Ya hay varias buenas respuestas, pero aquí hay una solución de estilo de paso continuo que puede ser útil (tal vez no para este ejemplo en particular, pero en otros contextos donde se desea una especie de sintaxis de aplicación inversa).
Con definiciones estándar para algunos tipos de dominio problemáticos:
puede introducir un tipo de paso continuo:
y escriba los tipos primitivos de construcción de notas para construir
Cont
tipos de esta manera:Luego, las funciones de construcción de escala, nota y acorde pueden resolver los
Cont
s en tipos simples en cualquier forma de postfijo (es decir, como continuaciones que se pasarán aCont
):o forma de prefijo (es decir, tomando
Cont
s como argumentos):Ahora puedes escribir:
Tenga en cuenta que
c
sí no tiene unaShow
instancia, peroc note
sí.Con una modificación al
Note
tipo, podría admitir fácilmente dobles accidentes (por ejemploc sharp sharp
, distintos ded
), etc.fuente
Cont
, sin embargo, intenté pegarlo a los constructores enA | B | C ...
lugar de usar funciones. No pude hacer que esto funcionara y todavía no entiendo por qué, dado que los constructores de valores son solo funciones. Si puedo pegar una función delante de mis teclas, muchas cosas se vuelven posibles. Si la función esflip ($)
entonces obtengo tu patrónflip ($) B :: Cont Key r
. Mi originalaScale = scale C Major
no es muy diferente.Puede usar las clases de tipos para solucionar eso inteligentemente:
Ahora, puede usar las letras minúsculas para otros tipos también definiendo instancias apropiadas.
fuente