Я столкнулся с небольшой эстетической проблемой в моем музыкальном проекте, и это беспокоило меня в течение некоторого времени.
У меня есть тип, data Key = C | D | ...
и я могу построить Scale
из а Key
и а Mode
. В Mode
различает , например , крупный и незначительный масштаб.
Я могу определить Mode
тип как функцию от Key
до Scale
. В этом случае режимы будут иметь имена в нижнем регистре (это нормально), и я могу получить такой масштаб
aScale = major C
Но музыканты так не разговаривают. Они называют эту шкалу C-мажорной шкалой, а не мажорной C- шкалой.
Что я хочу
В идеале я бы хотел написать
aScale = C major
Это вообще возможно?
Что я пробовал
Я могу сделать Key
функцию, которая строит Scale
из Mode
, так что я могу написать
aScale = c Major
Но я не могу ограничивать Ключи конструированием Весов. Они нужны и для других вещей (например, для создания аккордов ). Также Key
должен быть экземпляр Show
.
Я могу поставить Mode
после того, Key
когда я использую дополнительную функцию (или конструктор значений):
aScale = scale C major
с scale :: Key -> Mode -> Scale
Но лишнее слово « весы» выглядит шумно и, вопреки своему названию, на scale
самом деле не касается весов. Интеллектуальная часть находится в major
, scale
на самом деле просто flip ($)
.
Использование действительно newtype Mode = Major | Minor ...
ничего не меняет, за исключением того, что scale
должно быть более умным:
aScale = scale C Major
major C
.Ответы:
Решение 1:
Использовать этот
Теперь вы можете написать (с заглавной С и заглавной М)
Решение 2а:
Это тоже возможно
Теперь пишешь
Решение 2b:
Это тоже возможно
Теперь пишешь
источник
Вот одно причудливое решение, которое я не очень рекомендую, но выглядит очень «музыкально»:
Тогда вы можете написать
Конечно, на что это действительно направлено, так это то, что вы бы тоже имели
F♯ minor
иB♭ major
т.д.источник
⠀
U + 2800 БРАЙЛЛ ШАБЛОН ПУСТА можно использовать как инфикс. Само собой разумеется, это ужасная идея ... Все действительные символы пробела запрещены как инфиксы, но неудивительно, что Unicode содержит что-то, что может быть взломано в целях злоупотребления.Если вы не возражаете против дополнительного оператора, вы можете использовать
&
сData.Function
. Предполагая, чтоmajor
это функцияKey -> Scale
, вы можете написатьC & major
. Это даетScale
значение:источник
Уже есть несколько хороших ответов, но вот решение в стиле передачи продолжения, которое может быть полезным (возможно, не для этого конкретного примера, но в других контекстах, где требуется своего рода синтаксис обратного приложения).
Со стандартными определениями для некоторых типов проблемных областей:
Вы можете ввести тип продолжения:
и напишите примитивные типы создания заметок для создания
Cont
типов следующим образом:Затем функции построения, примечания и создания аккордов могут преобразовывать
Cont
s в простые типы в любой форме постфикса (т. Е. Как продолжения, передаваемые вCont
):или префикс формы (т. е. принимая
Cont
s в качестве аргументов):Теперь вы можете написать:
Обратите внимание, что
c
сам по себе не имеетShow
экземпляра, ноc note
есть.С изменением
Note
типа вы можете легко поддерживать двойные случайные (напримерc sharp sharp
, отличные отd
) и т. Д.источник
Cont
однако, я пытался привязать ее к конструкторамA | B | C ...
вместо использования функций. Я не мог заставить это работать, и я все еще не понимаю почему, учитывая, что конструкторы значений - это просто функции. Если я могу поставить функцию перед своими ключами, многое станет возможным. Если функция,flip ($)
то я получаю ваш шаблонflip ($) B :: Cont Key r
. Мой оригиналaScale = scale C Major
мало чем отличается.Вы можете использовать классы типов, чтобы ловко обойти это:
Теперь вы можете использовать строчные буквы и для других типов, определив соответствующие экземпляры.
источник