通常,当您希望被调用方能够选择类型参数的值而不是调用方时,可以使用更高级别的多态性。例如:
f :: (forall a. Show a => a -> Int) -> (Int, Int)
f g = (g "one", g 2)
任何功能g
,我传递给这个f
必须能够给我Int
一些类型,其中的值仅事情g
知道该类型是它的一个实例Show
。所以这些是洁净的:
f (length . show)
f (const 42)
但是这些不是:
f length
f succ
一个特别有用的应用程序是使用类型范围来强制值范围。假设我们有一个type对象Action<T>
,它表示可以运行以产生type结果的动作T
,例如future或callback。
T runAction<T>(Action<T>)
runAction :: forall a. Action a -> a
现在,假设我们还有一个Action
可以分配Resource<T>
对象的对象:
Action<Resource<T>> newResource<T>(T)
newResource :: forall a. a -> Action (Resource a)
我们要强制这些资源仅在Action
创建资源的内部使用,而不能在不同操作或同一操作的不同运行之间共享,因此操作是确定性和可重复的。
我们可以使用排名更高的类型来实现此目的,方法是S
在Resource
和Action
类型上添加一个完全抽象的参数-它代表的“作用域” Action
。现在我们的签名是:
T run<T>(<S> Action<S, T>)
Action<S, Resource<S, T>> newResource<T>(T)
runAction :: forall a. (forall s. Action s a) -> a
newResource :: forall s a. a -> Action s (Resource s a)
现在,当我们给出runAction
an时Action<S, T>
,我们可以放心,因为“ scope”参数S
是完全多态的,因此它无法转义的主体,runAction
因此使用S
诸如此类的任何类型的值Resource<S, int>
同样也无法转义!
(在Haskell中,这称为ST
monad,在其中runAction
被称为runST
,Resource
被称为STRef
,并且newResource
被称为newSTRef
。)
let sdff = (g : (f : <T> (e : T) => void) => void) => {}