eno*_*ram 5 haskell constraints constraint-kinds
我一直在玩一些GHC扩展来定义一个可以执行以下操作的函数:
let a = A :: A -- Show A
b = B :: B -- Show B
in
myFunc show a b -- This should return (String, String)
Run Code Online (Sandbox Code Playgroud)
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)
Run Code Online (Sandbox Code Playgroud)
我的主要目的是了解这些扩展如何工作; 但在我看来,似乎我告诉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
Run Code Online (Sandbox Code Playgroud)
我错过了什么?
问题是只是将函数(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)
Run Code Online (Sandbox Code Playgroud)
然后
let (c, d) = myFunc (Proxy :: Proxy Show) show a b
Run Code Online (Sandbox Code Playgroud)