Bu @n
, modern Haskell'in, genellikle LYAH gibi öğreticiler tarafından kapsanmayan ve Rapor'da bulunmayan gelişmiş bir özelliğidir.
Buna tip uygulaması denir ve GHC dil uzantısıdır. Bunu anlamak için bu basit polimorfik fonksiyonu düşünün
dup :: forall a . a -> (a, a)
dup x = (x, x)
Sezgisel olarak arama dup
şu şekilde çalışır:
- Arayan bir seçer türü
a
- Arayan bir seçer değeri
x
, önceden seçilen Çeşidia
dup
sonra bir tür değeri ile cevaplar (a,a)
Bir anlamda dup
iki argüman alır: tür a
ve değer x :: a
. Bununla birlikte, GHC genellikle türü çıkarabilir a
(örneğin x
, kullandığımız bağlamdan veya bağlamdan dup
), bu nedenle genellikle yalnızca bir argümanı dup
, yanix
. Örneğin,
dup True :: (Bool, Bool)
dup "hello" :: (String, String)
...
Şimdi, ya a
açıkça geçmek istersek ? Bu durumda, TypeApplications
uzantıyı açabilir ve yazabiliriz
dup @Bool True :: (Bool, Bool)
dup @String "hello" :: (String, String)
...
Not edin @...
Türleri taşıyan değişkenleri (değerleri değil). Bunlar sadece derleme zamanında var olan bir şeydir - çalışma zamanında argüman mevcut değildir.
Bunu neden istiyoruz? Bazen x
etrafta bir şey yok ve derleyiciyi doğru seçmesi için prod etmek istiyoruz a
. Örneğin
dup @Bool :: Bool -> (Bool, Bool)
dup @String :: String -> (String, String)
...
Tür uygulamaları genellikle belirsiz türler veya tür aileleri gibi tür çıkarımı GHC için olanaksız kılan diğer bazı uzantılarla birlikte kullanışlıdır. Bunları tartışmayacağım, ancak bazen güçlü tip seviyesi özellikleri kullanırken derleyiciye gerçekten yardımcı olmanız gerektiğini anlayabilirsiniz.
Şimdi, özel durumunuz hakkında. Ben kütüphaneyi bilmiyorum tüm ayrıntıları yok, ama çok büyük olasılıkla sizin de bu n
doğal sayısı değerine bir tür temsil tür düzeyinde . Burada, yukarıda belirtilenler artı DataKinds
, belki GADTs
ve bazı daktilo makineleri gibi oldukça gelişmiş uzantılara dalıyoruz. Her şeyi açıklayamasam da, umarım bazı temel bilgiler verebilirim. sezgisel,
foo :: forall n . some type using n
argüman olarak @n
, çalışma zamanında aktarılmayan bir tür derleme zamanı doğaldır. Yerine,
foo :: forall n . C n => some type using n
sürer @n
birlikte bir ile, (derleme zamanı) ispat o n
karşılar sınırlamak C n
. Sonuncusu, gerçek değerini ortaya çıkarabilecek bir çalışma zamanı bağımsız değişkenidir n
. Gerçekten, sizin durumunuzda, sanırım benzeyen bir şeyiniz var
value :: forall n . Reflects n Int => Int
bu da kodun doğal olarak tip-seviyesini terim-seviyesine getirmesine, esas olarak "tip" e "değer" olarak erişmesine izin verir. (Bu tür bir "belirsiz" olarak kabul edilir, bu arada - gerçekten @n
de belirsizleştirmek gerekir .)
Son olarak n
, daha sonra bunu terim seviyesine dönüştürürsek neden tür seviyesinde geçmek istesin ki? Gibi fonksiyonları yazmak daha kolay olmazdı
foo :: Int -> ...
foo n ... = ... use n
daha hantal yerine
foo :: forall n . Reflects n Int => ...
foo ... = ... use (value @n)
Dürüst cevap: evet, daha kolay olurdu. Ancak, n
tür düzeyinde olması, derleyicinin daha statik denetimler gerçekleştirmesine olanak tanır. Örneğin, bir türün "tamsayı modulo n
" u temsil etmesini ve bunların eklenmesine izin vermesini isteyebilirsiniz . sahip olan
data Mod = Mod Int -- Int modulo some n
foo :: Int -> Mod -> Mod -> Mod
foo n (Mod x) (Mod y) = Mod ((x+y) `mod` n)
çalışır, ancak hiçbir onay yoktur x
ve y
aynı modüllü olmaktadırlar. Eğer dikkatli olmazsak, elma ve portakal ekleyebiliriz. Bunun yerine yazabiliriz
data Mod n = Mod Int -- Int modulo n
foo :: Int -> Mod n -> Mod n -> Mod n
foo n (Mod x) (Mod y) = Mod ((x+y) `mod` n)
ki bu daha iyidir, ancak olmasa foo 5 x y
bile aramaya izin verir . İyi değil. Yerine,n
5
data Mod n = Mod Int -- Int modulo n
-- a lot of type machinery omitted here
foo :: forall n . SomeConstraint n => Mod n -> Mod n -> Mod n
foo (Mod x) (Mod y) = Mod ((x+y) `mod` (value @n))
şeylerin yanlış gitmesini önler. Derleyici statik olarak her şeyi kontrol eder. Kodun kullanımı daha zordur, evet, ancak bir bakıma kullanımı zorlaştırmak bütün mesele: kullanıcının yanlış modüllerden bir şey eklemeyi denemesini imkansız kılmak istiyoruz.
Sonuç: bunlar çok gelişmiş uzantılardır. Yeni başlayan biriyseniz, bu tekniklere doğru yavaşça ilerlemeniz gerekecektir. Kısa bir çalışmadan sonra onları kavrayamıyorsanız cesaretiniz kırılmasın, biraz zaman alır. Her seferinde küçük bir adım atın, her bir özellik için noktasını anlamak için bazı alıştırmaları çözün. Ve takılıp kaldığınızda her zaman StackOverflow'a sahip olacaksınız :-)