在 Haskell 中接收具有约束存在性的参数函数
Receiving as Argument Functions with Constrained Existentials in 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
的签名中应该是完全多态的,这样它就可以接受满足Show
的不同类型的a
和b
。
这是我对 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
和 return 一个特定的 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
我错过了什么?
问题在于,仅将函数 (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
我一直在使用一些 GHC 扩展来定义一个可以执行以下操作的函数:
let a = A :: A -- Show A
b = B :: B -- Show B
in
myFunc show a b -- This should return (String, String)
myFunc
在show
的签名中应该是完全多态的,这样它就可以接受满足Show
的不同类型的a
和b
。
这是我对 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
和 return 一个特定的 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
我错过了什么?
问题在于,仅将函数 (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