Alt parametre için fonksiyon parametre tipi olarak kullanım durumu var mı?


12

Bir fonksiyonun dönüş tipi ⊥ ( alt tip ) ise, bu asla geri dönmeyeceği anlamına gelir. Örneğin, her ikisi de oldukça sıradan durumlardan çıkabilir veya fırlayabilir.

Bir işlevin type türünde bir parametresi varsa, muhtemelen (güvenli bir şekilde) çağrılamaz. Böyle bir işlevi tanımlamak için herhangi bir neden var mı?

Yanıtlar:


17

veya boş türün tanımlayıcı özelliklerinden biri, her türü için işlevinin olmasıdır . Aslında, böyle eşsiz bir işlev vardır. Bu nedenle, bu fonksiyonun standart kütüphanenin bir parçası olarak sağlanması oldukça mantıklıdır. Genellikle buna benzer bir şey denir . (Alt tiplerinin sahip sistemlerde, bu sahip basitçe ele olabilir her tür bir alt tipi olabilir. Daha sonra kapalı dönüşümdür . Başka ilgili bir yaklaşım olan tanımlamak olarak basit olabilir örneği için her hangi bir tür.)AAα . αabsurdabsurd α.α

Kesinlikle böyle bir işleve veya eşdeğere sahip olmak istiyorsunuz çünkü üreten işlevleri kullanmanıza izin veren şey budur . Diyelim ki bana bir tür türü verildi . Ben bir vaka analizi yapmak ve durumda kullanarak bir istisna . In durumda, ben kullanacağız . Genel olarak, ben tip bir değerini istediğiniz ben çevirmek için bir şeyler yapmak gerek bu yüzden bir içine . Bunu yapmama izin veren buydu .E+AEthrow:EAf:ABBBabsurd

Bununla birlikte, kendi işlevlerinizi tanımlamak için pek bir neden yoktur . Tanım gereği, bunlar mutlaka birer örnek olacaktır . Yine de, standart kitaplık tarafından sağlanmadıysa veya tür denetleme / çıkarımına yardımcı olmak için özel bir tür sürüm istiyorsanız bunu yapabilirsiniz. Bununla birlikte, gibi bir türle sonuçlanacak işlevleri kolayca üretebilirsiniz .AAabsurdabsurdA

Böyle bir işlevi yazmak için fazla bir neden olmasa da, genellikle buna izin verilmelidir . Bunun bir nedeni, kod oluşturma araçlarını / makrolarını basitleştirmesidir.


Yani bu (x ? 3 : throw new Exception())analiz amaçlı bir şeyin yerine daha çok benzer bir şey (x ? 3 : absurd(throw new Exception()))mi?
bdsl

Alt türünüz yoksa veya olarak tanımlamamış olsaydınız, ilk önce check yazmaz ve sonuncusu olur. Alt tiplemeyle, evet, örtük olarak böyle bir şey eklenir. Tabii ki, içine olarak tanımlayan şeyin tanımını etkili bir şekilde koyabilirsiniz . α . α α . αα.αabsurdabsurdthrowα.α
Derek Elkins SE

6

İşlev hakkında söylenenlere eklemek için, absurd: ⊥ -> abu işlevin gerçekte nerede yararlı olduğuna dair somut bir örneğim var.

Şeklinde düğümler ve yapraklar içeren Free f agenel bir ağaç yapısını temsil eden Haskell veri türünü göz önünde bulundurun :fa

data Free f a = Op (f (Free f a)) | Var a

Bu ağaçlar aşağıdaki işlevle katlanabilir:

fold :: Functor f => (a -> b) -> (f b -> b) -> Free f a -> b
fold gen alg (Var x) = gen x
fold gen alg (Op x) = alg (fmap (fold gen alg) x)

Kısaca, bu operasyon algdüğümlere ve genyapraklara yerleştirilir.

Şimdi noktaya gelelim: tüm özyinelemeli veri yapıları Sabit Noktalı veri tipi kullanılarak temsil edilebilir. Haskell'de bu Fix fve şu şekilde tanımlanabilir type Fix f = Free f ⊥(yani, fşekilli düğümleri olan ağaçlar ve fonksiyonun dışında yaprakları yoktur f). Geleneksel olarak bu yapının da bir katlaması vardır cata:

cata :: Functor f => (f a -> a) -> Fix f -> a
cata alg x = fold absurd alg x

Bu oldukça saçma bir kullanım sağlar: ağacın herhangi bir yaprağı olamaz (than dışında hiçbir sakini olmadığından undefined), genbu kat için asla kullanmak mümkün değildir ve bunu absurdgöstermektedir!


2

Alt tip, uygulamada son derece yararlı olabilecek diğer her türün bir alt tipidir. Örneğin, NULLC'nin teorik tipte güvenli bir versiyonundaki tip, diğer her işaretçi tipinin bir alt tipi olmalıdır, aksi takdirde örneğin a'nın beklendiği NULLyere geri dönemezsiniz char*; benzer şekilde, undefinedteorik tipte güvenli JavaScript'in türü, dildeki diğer tüm türlerin bir alt türü olmalıdır.

Bir işlev geri dönüş tipi olarak, asla geri dönmeyen belirli işlevlere sahip olmak da çok yararlıdır. İstisnalar içeren, güçlü bir dilde yazılmış bir dilde, örneğin, hangi tür exit()ya da throw()geri dönmeli? Kontrol akışını asla arayanlarına geri döndürmezler. Ve alt tür diğer her türün bir alt türü olduğundan, bunun Intyerine return bot'a dönen bir işlev için mükemmel bir şekilde geçerlidir ; yani, dönen bir işlev de geri dönmemeyi seçebilir. (Belki çağırır , ya da sonsuz bir döngüye girer.) Bunu yapmak iyidir, çünkü bir fonksiyonun geri dönüp dönmediği ünlü olarak kararsızdır.Intexit()

Son olarak, kısıtlamalar yazmak için çok faydalıdır. "Her iki taraftaki" tüm parametreleri sınırlamak istediğinizi varsayalım, parametrenin bir üst tipi olması gereken bir tür ve bir alt tür olması gereken başka bir tür de sağlayın. Alt, her türden bir alt tür olduğundan, "S'nin herhangi bir alt türünü" . Veya "herhangi bir türü" .TST


3
NULLbirim tipi değil mi, boş tip hangisi?
bdsl

Tip teorisinde ≺ ne anlama geldiğinden tam olarak emin değilim.
bdsl

1
@bdsl Buradaki eğri işleç "bir alt tipidir"; Standart olup olmadığından emin değilim, sadece profesörüm bunu kullandı.
Draconis

1
@ gnasher729 Doğru, ancak C de tip güvenli değil. Sadece bir tamsayı atamazsanız void*, bunun için herhangi bir işaretçi türü için kullanılabilecek belirli bir türe ihtiyacınız olduğunu söylüyorum.
Draconis

2
Bu arada, alt tiplemesi ilişkisi için gördüğüm en sık notasyondur <:örn SistemiF<: .
Derek Elkins SE

2

Düşünebileceğim bir kullanım var ve bu, Swift programlama dilinde bir gelişme olarak kabul edildi.

Swift'in bir maybeMonad'ı vardır, hecelenmiş Optional<T>veya T?. Bununla etkileşime girmenin birçok yolu vardır.

  • Koşullu açmayı şu şekilde kullanabilirsiniz:

    if let nonOptional = someOptional {
        print(nonOptional)
    }
    else {
        print("someOptional was nil")
    }
    
  • Sen kullanabilirsiniz map, flatMapdeğerlerini dönüştürmek için

  • İçeriği zorla açmak için operatörü ( !türden (T?) -> T) zorla, aksi takdirde bir çökmeyi tetikler
  • Değerini almak veya başka bir varsayılan değer kullanmak için nil birleştirme operatörü ( ??, tür (T?, T) -> T):

    let someI = Optional(100)
    print(someI ?? 123) => 100 // "left operand is non-nil, unwrap it.
    
    let noneI: Int? = nil
    print(noneI ?? 123) // => 123 // left operand is nil, take right operand, acts like a "default" value
    

Maalesef, "paketini aç veya bir hata at" veya "özel bir hata iletisiyle paketini aç veya kilitle" demenin kısa bir yolu yoktu. Gibi bir şey

let someI: Int? = Optional(123)
let nonOptionalI: Int = someI ?? fatalError("Expected a non-nil value")

Çünkü, derleme yapmaz fatalErrortürü vardır () -> Never( ()olduğu Void, Swift'in' birimi türü, NeverSwift'in alt türüdür). Onu çağırmak üretilir Never, bu da Tdoğru işlenen olarak beklenen ile uyumlu değildir ??.

Bunu düzeltmek için Swift Evolution propsoal SE-0217- “ Paketten Çıkar veya Öl” operatörü ortaya atıldı. Bu edilmiş sonuçta reddedilen , ancak yapımında ilgi kaldırdı Nevertüm türlerinin bir alt tipi be.

Eğer Neverher türlü bir alt tipi olduğu için yapıldı, daha sonra önceki örnek derlenebilir olacaktır:

let someI: Int? = Optional(123)
let nonOptionalI: Int = someI ?? fatalError("Expected a non-nil value")

çünkü çağrı sitesinin imzasıyla uyumlu olan ??türü vardır .(T?, Never) -> T(T?, T) -> T??


0

Swift, alt türe benzeyen bir "Never" tipine sahiptir: Geri döndüğü bildirilen bir işlev Hiçbir zaman geri dönemez, Never türünde bir parametreye sahip bir işlev asla çağrılamaz.

Bu, bir sınıfın belirli bir işlevi olması gereken dilin tür sistemi nedeniyle bir kısıtlama olabileceği, ancak bu işlevin çağrılması gerekmediği ve bağımsız değişken türlerinin herhangi bir şartı bulunmadığı protokollerle bağlantılı olarak yararlıdır. olabilir.

Ayrıntılar için hızlı evrim posta listesindeki yeni yayınlara bir göz atmalısınız.


7
"Hızlı evrim posta listesindeki daha yeni gönderiler" çok açık veya istikrarlı bir referans değildir. Posta listesinin web arşivi yok mu?
Derek Elkins SE
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.