Проблема
Розглянемо наступну проблему дизайну в Haskell. У мене є простий, символічний EDSL, в якому я хочу висловити змінні та загальні вирази (багатоваріантні многочлени), такі як x^2 * y + 2*z + 1
. Крім того, я хочу висловити певні символічні рівняння над виразами, скажімо x^2 + 1 = 1
, так само, як і визначення , як x := 2*y - 2
.
Мета:
- Мають окремий тип змінних та загальних виразів - певні функції можуть застосовуватися до змінних, а не до складних виразів. Наприклад, оператор визначення
:=
може бути типу,(:=) :: Variable -> Expression -> Definition
і він не повинен бути можливим передавати складний вираз як його лівий параметр (хоча він повинен мати можливість передавати змінну як її правий бічний параметр, без явного введення ) . - Майте вирази примірник
Num
, щоб можна було просувати цілі літерали до виразів і використовувати зручне позначення для загальних алгебраїчних операцій, таких як додавання чи множення, без введення деяких допоміжних операторів обгортки.
Іншими словами, я хотів би мати неявний і статичний тип передачі (примусу) змінних до виразів. Тепер я знаю, що в такому випадку в Haskell немає чітких типів неявного типу. Тим не менш, певні об'єктно-орієнтовані концепції програмування (просте успадкування в даному випадку) є виразними в системі типів Haskell, з мовними розширеннями або без них. Як я міг задовольнити обидва вищезазначені моменти, зберігаючи легкий синтаксис? Чи можливо це навіть?
Обговорення
Зрозуміло, що головна проблема тут - Num
обмеження типу, наприклад
(+) :: Num a => a -> a -> a
В принципі, можна написати єдиний (узагальнений) алгебраїчний тип даних як для змінних, так і для виразів. Тоді можна було написати :=
таким чином, що вираз лівого боку дискримінується і приймається лише змінний конструктор, інакше помилка виконання. Це, однак, не чисте, статичне (тобто час збирання) ...
Приклад
В ідеалі я хотів би досягти легкого синтаксису, такого як
computation = do
x <- variable
t <- variable
t |:=| x^2 - 1
solve (t |==| 0)
Зокрема, я хочу заборонити позначення, як,
t + 1 |:=| x^2 - 1
оскільки :=
слід дати визначення змінної, а не цілого виразу зліва.
FromVar
чим би допомагав тип класу. Я хочу уникати явних кастів, зберігаючи Expr
примірник Num
. Я редагував питання, додаючи приклад нотації, яку я хотів би досягти.
class FromVar e
методомfromVar :: Variable -> e
і вказати екземпляри для,Expression
аVariable
потім ваші змінні мають поліморфні типиx :: FromVar e => e
тощо. Я не перевіряв, наскільки добре це працює, оскільки я зараз на своєму телефоні.