Yüksek rütbeli parametrik polimorfizm faydalı mıdır?


16

Herkesin formun genel yöntemlerine aşina olduğundan eminim:

T DoSomething<T>(T item)

Bu fonksiyon parametrik olarak polimorfik (PP), özellikle rank-1 PP olarak da adlandırılır .

Bu yöntemin, formun bir işlev nesnesi kullanılarak temsil edilebileceğini varsayalım:

<T> : T -> T

Yani, <T>bir tür parametresi alır ve bir tür parametresi T -> Talır Tve aynı türden bir değer döndürür.

Sonra aşağıdaki rütbe-2 PP fonksiyonu olacaktır:

(<T> : T -> T) -> int 

İşlev hiçbir tür parametresini kendisi almaz, ancak bir tür parametresi alan bir işlevi alır. Buna yinelemeli olarak devam edebilir, iç içe geçmeyi daha derin ve daha derin hale getirerek PP'yi daha yüksek ve daha yüksek bir sıraya getirebilirsiniz.

Bu özellik programlama dilleri arasında gerçekten nadirdir. Haskell bile varsayılan olarak buna izin vermez.

Yararlı mı? Başka türlü tanımlanması zor davranışları tarif edebilir mi?

Ayrıca, bir şeyin öngörülemez olması ne anlama gelir ? (bu içerikte)


1
İlginçtir ki, TypeScript tam rank-n PP desteğine sahip ana akım bir dildir. Örneğin, aşağıdakiler geçerli bir TypeScript kodudur:let sdff = (g : (f : <T> (e : T) => void) => void) => {}
GregRos

Yanıtlar:


11

İstediğiniz zaman Genel olarak, daha yüksek rütbe polimorfizm kullanmak Aranan ziyade, bir tür parametresinin değerini seçmek için muktedir arayan . Örneğin:

f :: (forall a. Show a => a -> Int) -> (Int, Int)
f g = (g "one", g 2)

gBunu ilettiğim herhangi bir işlev fbana bir Inttür bir değer verebilmeli , bu tür hakkında tek şey gbilir bir örneği vardır Show. Yani bunlar koşer:

f (length . show)
f (const 42)

Ancak bunlar:

f length
f succ

Özellikle kullanışlı bir uygulama, değerlerin kapsamını uygulamak için tiplerin kapsamını kullanmaktır . Gelecekteki veya geri arama gibi bir tür sonucu üretmek için gerçekleştirebileceğimiz bir eylemi temsil eden bir tür nesnemiz olduğunu varsayalım .Action<T>T

T runAction<T>(Action<T>)

runAction :: forall a. Action a -> a

Şimdi, nesneleri Actionayırabilecek bir tane de olduğunu varsayalım Resource<T>:

Action<Resource<T>> newResource<T>(T)

newResource :: forall a. a -> Action (Resource a)

Bu kaynakların yalnızcaAction oluşturuldukları yerde kullanılmasını ve aynı eylemin farklı eylemleri veya farklı eylemleri arasında paylaşılmamasını zorunlu kılmak istiyoruz , böylece eylemler belirleyici ve tekrarlanabilir.

Bir parametre ekleyerek bunu gerçekleştirmek için daha yüksek sıralarda yer türlerini kullanabilirsiniz Setmek Resourceve Actiontamamen soyut-bunun “kapsamını” temsil olduğunu türleri, Action. Şimdi imzalarımız:

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)

Biz verince Şimdi runActionbir Action<S, T>, biz “kapsam” parametresi çünkü emin bulunmaktadır Stamamen polimorfik, bu gövdesini kaçamaz runAction-SO kullandığı bu bir tür herhangi bir değer Sgibi Resource<S, int>aynı şekilde kaçamaz!

(Haskell'de bu, adı verilen , adı verilen ve adı verilen STmonad olarak bilinir .)runActionrunSTResourceSTRefnewResourcenewSTRef


STMonad çok ilginç bir örnektir. Yüksek rütbeli polimorfizmin ne zaman yararlı olacağına dair daha fazla örnek verebilir misiniz?
GregRos

@GregRos: Varoluşlarla da kullanışlıdır. Gelen Haxl , biz varoluş gibi olsaydı data Fetch d = forall a. Fetch (d a) (MVar a), bir veri kaynağı için bir istek bir çift, dve sonucu depolamak için bir yuvaya. Sonuç ve alan eşleşen türlere sahip olmalıdır, ancak bu tür gizlidir, böylece aynı veri kaynağına yönelik heterojen bir istek listesine sahip olabilirsiniz. Artık bir tane getiren bir işlev verildiğinde, tüm istekleri getiren bir işlev yazmak için daha üst düzey polimorfizm kullanabilirsiniz fetch :: (forall a. d a -> IO a) -> [Fetch d] -> IO ().
Jon Purdy

8

Yüksek rütbeli polimorfizm son derece yararlıdır. Sistem F'de (aşina olduğunuz yazılan FP dillerinin temel dili), bu, aslında Sistem F'nin programlama yaptığı "yazılan Kilise kodlamaları" nı kabul etmek için gereklidir. Bunlar olmadan, F sistemi tamamen işe yaramaz.

Sistem F'de sayıları

Nat = forall c. (c -> c) -> c -> c

Toplama türü var

plus : Nat -> Nat -> Nat
plus l r = Λ t. λ (s : t -> t). λ (z : t). l s (r s z)

daha yüksek bir sıralama türüdür ( forall c.bu okların içinde görünür).

Bu başka yerlerde de ortaya çıkıyor. Örneğin, bir hesaplamanın uygun bir devam eden geçiş stili (google "codensity haskell") olduğunu belirtmek istiyorsanız, bunu şu şekilde düzeltirsiniz:

type CPSed A = forall c. (A -> c) -> c

Sistem F'de ıssız bir tip hakkında konuşmak bile daha yüksek rütbeli bir polimorfizm gerektirir

type Void = forall a. a 

Bunun uzun ve kısası, saf tip bir sistemde (Sistem F, CoC) bir fonksiyon yazmak, herhangi bir ilginç veriyle uğraşmak istiyorsak daha yüksek dereceli polimorfizm gerektirir.

Özellikle Sistem F'de, bu kodlamaların "imkansız" olması gerekir. Bu, kesinlikle tüm türlerforall a. üzerinde bir nicelik anlamına gelir . Bu, kritik olarak tanımladığımız türü içerir. Gelen o aslında için duramazdı daha! ML gibi diller bu durum böyle değil, sadece türleri kümesi üzerinden bir tip değişken ölçtüğü için "yüklem" olduğu söylenir ediyoruz olmadan Nicelik (adlandırılır monotypes). Tanımımız gerekli impredicativity biz örneği de çünkü sıra içinde olmak !forall a. aaforall a. apluscl : NatNat

Son olarak, keyfi olarak özyinelemeli türlerde (Sistem F'den farklı olarak) bile hem beklenmedikliği hem de daha yüksek dereceli polimorfizmin olmasını istediğiniz son bir nedenden bahsetmek istiyorum. Haskell'de, "durum iş parçacığı monad" olarak adlandırılan efektler için bir monad var. Fikir, devlet iş parçacığı monad bir şeyleri mutasyona izin verir, ancak sonuçtan değişebilir bir şeye bağlı olmadığından kaçmayı gerektirir. Bu, ST hesaplamalarının gözle görülür derecede saf olduğu anlamına gelir. Bu şartı uygulamak için daha yüksek rütbeli polimorfizm kullanıyoruz

runST :: forall a. (forall s. ST s a) -> a

Burada abunun tanıttığımız kapsamın dışında kalmasını sağlayarak, bunun güvenilmeyen iyi biçimlendirilmiş bir tür anlamına sgeldiğini biliyoruz . Biz kullanmak bunu biliyoruz bu nedenle söz konusu devlet dizideki tüm değişken şeyleri parameritize için değişken şeylerin bağımsızdır ve hiçbir şey kapsamını kaçar böylece o hesaplama! Kötü biçimli programları dışlamak için türlerin kullanılmasına harika bir örnek.assaST

Bu arada, tip teorisi hakkında bilgi edinmek istiyorsanız iyi bir kitaba yatırım yapmanızı öneririm. Bu şeyleri parça ve parça olarak öğrenmek zor. Pierce veya Harper'ın genel olarak PL teorisi (ve tip teorisinin bazı unsurları) hakkındaki kitaplarından birini öneririm. "Türlerde ve programlama dillerinde ileri konular" kitabı da iyi miktarda tür teorisini kapsamaktadır. Son olarak, "Martin Lof'un tür teorisinde programlama" Martin Lof'un özetlediği boyutlu tür teorisine çok iyi bir açıklamadır.


Önerileriniz için teşekkür ederiz. Onları arayacağım. Konu gerçekten ilginç ve keşke daha gelişmiş tip sistem kavramlarının daha fazla programlama dili tarafından benimsenmesini diliyorum. Size çok daha etkileyici bir güç veriyorlar.
GregRos
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.