Мой опыт показывает, что подслащивание каждого термина интуитивно кажется непривлекательным, но его стоит продолжить.
Интерес к постоянному хранению побудил меня обходным путем рассмотреть проблемы смешивания выражения и атомарных значений. Чтобы поддержать это, я решил разделить их полностью в системе типов; таким образом, Int, Char и т. д. являются конструкторами типов только для целочисленных и символьных значений. Типы выражений формируются с помощью конструктора полиморфных типов Exp; например Exp Int относится к значению, которое уменьшается за один шаг до Int.
Соответствие этого вашему вопросу возникает, когда мы рассматриваем оценку. На нижележащем уровне существуют примитивы, которые требуют атомарных значений: COND, addInt и т. Д. Некоторые люди называют это принудительным выражением, я предпочитаю видеть его просто как приведение между значениями различных типов.
Задача состоит в том, чтобы посмотреть, можно ли это сделать, не требуя явных директив сокращения. Одно из решений точно такое, как вы предлагаете: то есть рассматривать принуждение как форму перегрузки.
Скажем, у нас есть входной скрипт: foo x
Затем, после подслащивания, это становится: (coerce foo) (coerce x)
Где неофициально:
coerce :: a -> b
coerce x = REDUCE (cast x) if a and b are incompatible
x otherwise
Таким образом coerce является либо идентификатором, либо приложением cast , где b является типом возврата для данного контекста.
cast теперь можно рассматривать как метод класса типов, например
class Cast a, b where {cast :: a -> b };
-- ¬:: is an operator, literally meaning: don’t cast
--(!) is the reduction operator. Perform one stage of reduction.
-- Reduce on demand
instance Cast Exp c, c where { inline cast = ¬::(!)(\x::(Exp c) -> ¬::(!)x) };
Аннотации ¬::
используются для подавления принудительного синтаксического подсахаривания.
Предполагается, что другие экземпляры Cast
могут быть введены для расширения диапазона конверсий, хотя я не исследовал это. Как вы говорите, перекрывающиеся экземпляры кажутся необходимыми.