W moim projekcie muzycznym napotkałem niewielki problem estetyczny i od pewnego czasu mnie to denerwuje.
Mam typ data Key = C | D | ...
i mogę zbudować Scale
a Key
i a Mode
. W Mode
rozróżnia np główną i mniejszą skalę.
Mogę zdefiniować Mode
typ jako funkcję od Key
do Scale
. W takim przypadku tryby będą miały małe litery (co jest w porządku) i mogę uzyskać taką skalę
aScale = major C
Ale muzycy tak nie mówią. Odnoszą się do tej skali jako do skali C-dur , a nie do skali C-dur .
Czego chcę
Idealnie chciałbym pisać
aScale = C major
Czy to w ogóle jest możliwe?
Co próbowałem
Mogę stworzyć Key
funkcję, która konstruuje Scale
z a Mode
, więc mogę pisać
aScale = c Major
Ale nie mogę ograniczyć kluczy do budowania Łusków. Są one również potrzebne do innych rzeczy (np. Do tworzenia akordów ). Key
Powinien też być przypadek Show
.
Mogę umieścić Mode
po, Key
kiedy używam dodatkowej funkcji (lub konstruktora wartości):
aScale = scale C major
z scale :: Key -> Mode -> Scale
Ale dodatkowa skala słów wygląda głośno i wbrew nazwie, scale
tak naprawdę nie dotyczy skal. Inteligentna część jest w środku major
, scale
jest naprawdę sprawiedliwa flip ($)
.
Używanie newtype Mode = Major | Minor ...
naprawdę niewiele się zmienia, poza tym scale
musi być bardziej inteligentny:
aScale = scale C Major
major C
.Odpowiedzi:
Rozwiązanie 1:
Użyj tego
Teraz możesz pisać (z dużą literą C i wielką literą M)
Rozwiązanie 2a:
Jest to również możliwe
Teraz piszesz
Rozwiązanie 2b:
Jest to również możliwe
Teraz piszesz
źródło
Oto jedno kapryśne rozwiązanie, którego tak naprawdę nie polecam, ale wygląda bardzo „muzykalnie”:
Potem możesz pisać
Oczywiście, tam gdzie to jest naprawdę celowane jest to, że Ty też miałbyś
F♯ minor
iB♭ major
itp.źródło
⠀
U + 2800 BRAILLE PATTERN BLANK może być użyty jako infix. Nie trzeba dodawać, że to okropny pomysł ... Wszystkie rzeczywiste znaki spacji są zabronione jako poprawki, ale nic dziwnego, że Unicode zawiera coś, co można zhakować w celu nadużycia.Jeśli nie przeszkadza ci dodatkowy operator, możesz skorzystać
&
zData.Function
. Zakładając, żemajor
jest to funkcjaKey -> Scale
, możesz pisaćC & major
. To dajeScale
wartość:źródło
Istnieje już kilka dobrych odpowiedzi, ale oto rozwiązanie w stylu przechodzenia kontynuacji, które może być pomocne (może nie w tym konkretnym przykładzie, ale w innych kontekstach, w których pożądana jest pewnego rodzaju składnia aplikacji odwrotnej).
Ze standardowymi definicjami dla niektórych typów domen problemowych:
możesz wprowadzić ciąg dalszy:
i napisz prymitywne typy budowania notatek, aby budować
Cont
takie typy:Następnie funkcje budowania skali, nuty i akordu mogą przekształcić
Cont
s na typy zwykłe w dowolnej postaci pofiksowej (tj. Jako kontynuacje, które zostaną przekazane doCont
):lub forma prefiksu (tj. przyjmowanie
Cont
s jako argumentu):Teraz możesz napisać:
Zauważ, że
c
sama nie maShow
instancji, alec note
ma.Dzięki modyfikacji
Note
typu można łatwo obsługiwać podwójne zdarzenia (np.c sharp sharp
Odróżnić odd
) itp.źródło
Cont
, próbowałem jednak przykleić go do konstruktorówA | B | C ...
zamiast używać funkcji. Nie mogłem tego uruchomić i nadal nie rozumiem dlaczego, biorąc pod uwagę, że konstruktory wartości są tylko funkcjami. Jeśli uda mi się nakleić funkcję przed klawiszami, wiele rzeczy stanie się możliwe. Jeśli funkcja jest,flip ($)
to dostaję twój wzórflip ($) B :: Cont Key r
. Mój oryginałaScale = scale C Major
nie różni się zbytnio.Możesz użyć klas, aby sprytnie obejść to:
Teraz możesz używać małych liter także dla innych typów, definiując odpowiednie wystąpienia.
źródło