Получение в качестве аргумента функций с ограниченными экзистенциалами в Haskell
Я играл с некоторыми расширениями GHC, чтобы определить функцию, которая может делать следующее:
let a = A :: A -- Show A
b = B :: B -- Show B
in
myFunc show a b -- This should return (String, String)
myFunc
должен быть полностью полиморфным в подписи show
чтобы он мог принять a
а также b
с различными типами, удовлетворяющими Show
,
Вот моя попытка с расширениями GHC RankNTypes
, ConstraintKinds
, KindSignatures
:
myFunc :: forall (k :: * -> Constraint) a b d. (k a, k b)
=> (forall c. k c => c -> d) -> a -> b -> (d, d)
Моя главная цель - понять, как работают эти расширения; но мне кажется, что я говорю GHC, что есть ограничение k
это что то a
а также b
удовлетворить, и есть также функция (forall c. k c => c -> d)
это может занять любой тип c
сытный k
и вернуть конкретный d
Теперь, в этих условиях, я хочу применить функцию к a
а также b
получить кортеж (d,d)
Вот как жалуется GHC:
Could not deduce (k0 a, k0 b)
from the context (k a, k b)
bound by the type signature for
myFunc :: (k a, k b) =>
(forall c. k c => c -> d) -> a -> b -> (d, d)
at app/Main.hs:(15,11)-(16,56)
In the ambiguity check for the type signature for ‘myFunc’:
myFunc :: forall (k :: * -> Constraint) a b d.
(k a, k b) =>
(forall c. k c => c -> d) -> a -> b -> (d, d)
To defer the ambiguity check to use sites, enable AllowAmbiguousTypes
In the type signature for ‘myFunc’:
myFunc :: forall (k :: * -> Constraint) a b d. (k a, k b) =>
(forall c. k c => c -> d) -> a -> b -> (d, d)
...
Could not deduce (k c)
from the context (k a, k b)
bound by the type signature for
myFunc :: (k a, k b) =>
(forall c. k c => c -> d) -> a -> b -> (d, d)
at app/Main.hs:(15,11)-(16,56)
or from (k0 c)
bound by the type signature for myFunc :: k0 c => c -> d
at app/Main.hs:(15,11)-(16,56)
In the ambiguity check for the type signature for ‘myFunc’:
myFunc :: forall (k :: * -> Constraint) a b d.
(k a, k b) =>
(forall c. k c => c -> d) -> a -> b -> (d, d)
To defer the ambiguity check to use sites, enable AllowAmbiguousTypes
In the type signature for ‘myFunc’:
myFunc :: forall (k :: * -> Constraint) a b d. (k a, k b) =>
(forall c. k c => c -> d) -> a -> b -> (d, d)
app/Main.hs15:40
Что мне не хватает?
1 ответ
Проблема в том, что просто передавая функцию (forall c . k c => c -> d)
в качестве аргумента для средства проверки типов недостаточно однозначно определить, что k
на самом деле. Передача ограничения явно работает, и вам даже не нужен внешний forall
или явные виды:
import Data.Proxy
myFunc :: (k a, k b) => Proxy k -> (forall c. k c => c -> d) -> a -> b -> (d, d)
myFunc _ f a b = (f a, f b)
а потом
let (c, d) = myFunc (Proxy :: Proxy Show) show a b