проблема
Рассмотрим следующую проблему дизайна в Haskell. У меня есть простой, символический EDSL, в котором я хочу выразить переменные и общие выражения (многомерные полиномы), такие как x^2 * y + 2*z + 1. Кроме того, я хочу выразить некоторые символические уравнения над выражениями, скажем x^2 + 1 = 1, а также определениями , например x := 2*y - 2.
Цель состоит в том, чтобы:
- Имейте отдельный тип для переменных и общих выражений - некоторые функции могут применяться к переменным, а не к сложным выражениям. Например, оператор определения
:=может иметь тип,(:=) :: Variable -> Expression -> Definitionи не должно быть возможности передавать сложное выражение в качестве параметра левой части (хотя должна быть возможность передавать переменную в качестве параметра правой части без явного приведения ). , - Имейте выражения в качестве экземпляра
Num, чтобы можно было добавлять целочисленные литералы в выражения и использовать удобные обозначения для общих алгебраических операций, таких как сложение или умножение, без введения некоторых вспомогательных операторов-оболочек.
Другими словами, я хотел бы иметь неявное и статическое приведение типов (приведение) переменных к выражениям. Теперь я знаю, что в Хаскеле нет неявных приведений типов. Тем не менее, некоторые объектно-ориентированные концепции программирования (простое наследование, в данном случае) являются выразимы в системе типов в 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и т. д. Я не проверял, насколько хорошо это работает, так как я сейчас на моем телефоне.