5

我一直在玩一些 GHC 扩展来定义一个可以执行以下操作的函数:

let a = A :: A  -- Show A
    b = B :: B  -- Show B
  in
    myFunc show a b -- This should return (String, String)

myFunc的签名应该是完全多态的show,这样它才能接受ab满足不同的类型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,现在,在这些条件下,我想应用该函数toabto 获得一个元组(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

我错过了什么?

4

1 回答 1

5

问题是仅仅将函数(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
于 2016-09-22T10:11:33.883 回答