У меня есть функция, задачей которой является вычисление некоторого оптимального значения типа a
для некоторой функции значения типа a -> v
type OptiF a v = (a -> v) -> a
Затем у меня есть контейнер, который хочет сохранить такую функцию вместе с другой функцией, которая использует значения:
data Container a = forall v. (Ord v) => Cons (OptiF a v) (a -> Int)
Идея состоит в том, что тот, кто реализует функцию типа OptiF a v
, не должен беспокоиться о деталях v
, за исключением того, что это экземпляр Ord
.
Итак, я написал функцию, которая принимает такую функцию значения и контейнер. Используя OptiF a v
, он должен вычислить оптимальное значение wrt val
и вставить его в контейнер result
:
optimize :: (forall v. (Ord v) => a -> v) -> Container a -> Int
optimize val (Cons opti result) = result (opti val)
Пока все хорошо, но я не могу назвать optimize
, потому что
callOptimize :: Int
callOptimize = optimize val cont
where val = (*3)
opti val' = if val' 1 > val' 0 then 100 else -100
cont = Cons opti (*2)
не компилируется:
Could not deduce (v ~ Int)
from the context (Ord v)
bound by a type expected by the context: Ord v => Int -> v
at bla.hs:12:16-32
`v' is a rigid type variable bound by
a type expected by the context: Ord v => Int -> v at bla.hs:12:16
Expected type: Int
Actual type: Int
Expected type: Int -> v
Actual type: Int -> Int
In the first argument of `optimize', namely `val'
In the expression: optimize val cont
где строка 12: 16-32 равна optimize val cont
.
Неужели я не понимаю экзистенциальных типов в этом случае? Является ли forall v
в объявлении optimize
означать, что optimize
может ожидать от a -> v
любого v
, который он хочет? Или это означает, что optimize
не может ничего ожидать от a -> v
, за исключением того, что Ord v
?
Я хочу, чтобы OptiF a v
не был исправлен для любого v
, потому что позже я хочу подключить некоторое a -> v
. Единственное ограничение, которое я хотел бы наложить, - Ord v
. Можно ли даже выразить что-то подобное с использованием экзистенциальных типов (или что-то еще)?
Мне удалось добиться этого с помощью дополнительного typeclass, который предоставляет функцию optimize
с аналогичной сигнатурой OptiF a v
, но для меня это выглядит намного уродливее, чем использование функций более высокого порядка.