通常,当您希望被调用方能够选择类型参数的值而不是调用方时,可以使用更高级别的多态性。例如:
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)
现在,当我们给出runActionan时Action<S, T>,我们可以放心,因为“ scope”参数S是完全多态的,因此它无法转义的主体,runAction因此使用S诸如此类的任何类型的值Resource<S, int>同样也无法转义!
(在Haskell中,这称为STmonad,在其中runAction被称为runST,Resource被称为STRef,并且newResource被称为newSTRef。)
let sdff = (g : (f : <T> (e : T) => void) => void) => {}