Nói chung, bạn sử dụng đa hình bậc cao hơn khi bạn muốn callee có thể chọn giá trị của một tham số loại, thay vì người gọi . Ví dụ:
f :: (forall a. Show a => a -> Int) -> (Int, Int)
f g = (g "one", g 2)
Bất kỳ chức năng g
nào tôi chuyển đến điều này f
phải có thể cung cấp cho tôi Int
từ một giá trị của một loại nào đó, trong đó điều duy nhất g
biết về loại đó là nó có một thể hiện của Show
. Vì vậy, đây là kosher:
f (length . show)
f (const 42)
Nhưng đây không phải là:
f length
f succ
Một ứng dụng đặc biệt hữu ích là sử dụng phạm vi của các loại để thực thi phạm vi giá trị . Giả sử chúng ta có một đối tượng của kiểu Action<T>
, đại diện cho một hành động mà chúng ta có thể chạy để tạo ra kết quả của loại T
, chẳng hạn như tương lai hoặc gọi lại.
T runAction<T>(Action<T>)
runAction :: forall a. Action a -> a
Bây giờ, giả sử rằng chúng ta cũng có một đối tượng Action
có thể phân bổ Resource<T>
các đối tượng:
Action<Resource<T>> newResource<T>(T)
newResource :: forall a. a -> Action (Resource a)
Chúng tôi muốn thực thi rằng các tài nguyên đó chỉ được sử dụng bên trong Action
nơi chúng được tạo và không được chia sẻ giữa các hành động khác nhau hoặc các hoạt động khác nhau của cùng một hành động, để các hành động có tính quyết định và có thể lặp lại.
Chúng ta có thể sử dụng các loại được xếp hạng cao hơn để thực hiện điều này bằng cách thêm một tham số S
cho Resource
và Action
các loại, đó là hoàn toàn trừu tượng, nó đại diện cho phạm vi của phạm vi Action
. Bây giờ chữ ký của chúng tôi là:
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)
Bây giờ khi chúng tôi đưa ra runAction
một Action<S, T>
, chúng tôi chắc chắn rằng vì tham số phạm vi phạm vi của chế độ S
đa hình, nó không thể thoát khỏi cơ thể của runAction
bất kỳ giá trị nào của một loại sử dụng S
như Resource<S, int>
vậy cũng không thể thoát!
(Trong Haskell, đây được gọi là ST
đơn nguyên, nơi runAction
được gọi runST
, Resource
được gọi STRef
và newResource
được gọi newSTRef
.)
let sdff = (g : (f : <T> (e : T) => void) => void) => {}