Burada, "değerler", "türler" ve "türler" resmi anlamlara sahiptir, bu nedenle ortak İngilizce kullanımlarını veya otomobilleri sınıflandırma analojilerini göz önünde bulundurmanız yalnızca size çok yardımcı olacaktır.
Cevabım, özellikle Haskell bağlamında bu terimlerin biçimsel anlamları ile ilgilidir; bu anlamlar matematikle / CS "tip teorisi" nde kullanılan anlamlara dayandırılmıştır (aslında aynı değildir). Yani, bu çok iyi bir "bilgisayar bilimi" cevabı olmayacak, ama oldukça iyi bir Haskell cevabı olarak hizmet etmeli.
Haskell'de (ve diğer dillerde), ifadenin sahip olmasına izin verilen değer sınıfını tanımlayan bir program ifadesine bir tür atamak yararlı olur . Ben bunu ifadede olduğunu bilmek faydalı olacaktır anlamak için yeterli örnek gördüm burada varsayıyoruz , değişkenler ve her zaman türünün değerlerini olacak değil, demek, ve sırasıyla. Temelde, sahip türlerini geniş bir yelpazede üzerinde düzgün çalışacağını ifadeleri / programların yazılı olarak bize yardımcı değerler .sqrt (a**2 + b**2)
a
b
Double
String
Bool
Şimdi, farkına varmamış olabileceğiniz bir şey, Haskell tiplerinin, tip imzalarında görünenlere benzemesidir:
fmap :: Functor f => (a -> b) -> f a -> f b
aslında kendileri de bir seviye-seviye Haskell alt dilinde yazılmıştır. Program metni Functor f => (a -> b) -> f a -> f b
- tam anlamıyla - bu alt dilde yazılmış bir tür ifadedir . Altdili (örneğin operatör içerir ->
bu dilde bir sağ taraf infix operatörüdür), değişkenler (örneğin f
, a
ve b
) diğerine tipi ifade ve "uygulama" (örneğin, f a
bir f
uygulanan a
).
İfade değerleri sınıflarını tanımlamak için program ifadelerine tipler atamanın birçok dilde nasıl bir faydası olduğunu söylemiş miydim? Eh, bu tip seviyeli alt dilde, ifadeler türlere ( değerlerden ziyade ) değerlendirilir ve temsil edilmelerine izin verilen türlerin sınıflarını tanımlamak için tür ifadelerine tür atamak yardımcı olur . Temel olarak, türlere sahip olmak, çok çeşitli türlerde doğru şekilde çalışacak türdeki yazım ifadelerinde bize yardımcı olur .
Yani, değerler şunlardır türleri olarak türleri şunlardır türlü ve türleri bize yazmanıza yardımcı değeri ise -seviye programlar türlü bize yazmanıza yardımcı tip -seviye programları.
Bu tür neye benziyor? Peki, imza türünü düşünün:
id :: a -> a
Tip ifadesi ise a -> a
geçerli olmak ne tür bir türlerine biz değişken izin vermeli a
olunur? Eh, tür ifadeleri:
Int -> Int
Bool -> Bool
geçerli görünüyor, bu yüzden türleri Int
ve Bool
açıkça doğru tür . Ancak daha karmaşık türler:
[Double] -> [Double]
Maybe [(Double,Int)] -> Maybe [(Double,Int)]
geçerli görünüyorsun Aslında, id
fonksiyonlara çağrı yapabilmemiz gerektiğinden bile:
(a -> a) -> (a -> a)
iyi görünüyor. Yani, Int
, Bool
, [Double]
, Maybe [(Double,Int)]
, ve a -> a
benzeri tüm göz tipleri hakkı tür .
Başka bir deyişle, sadece bir tane var gibi görünüyor tür , diyelim *
Unix joker gibi, her tip aynı vardır tür *
, hikayenin sonu.
Sağ?
Pek iyi değil. O çıkıyor Maybe
olarak tek başına bütün, sadece geçerli bir tür ifadesi olarak ise, Maybe Int
(hemen aynı şekilde sqrt
, tek başına bütün, tıpkı geçerli bir değer ifadesi gibidir sqrt 25
). Ancak , aşağıdaki tür ifadesi geçerli değil:
Maybe -> Maybe
Ederken, Çünkü Maybe
bir tür ifadesidir, bu temsil etmiyor tür bir tip değerlere sahip olabilir. Yani, işte biz tanımlamalıdır nasıl *
- bu tür bir türlerine değerlerine sahip; neye "tam" türlerini içerir Double
veya Maybe [(Double,Int)]
dışlayan eksik, değersiz türleri gibi ama Either String
. Basitlik için, *
bu terminoloji evrensel olmasa da, "somut türler" C ++ programcısından çok farklı bir şey anlamına gelebilir.
Şimdi, tip ifadesinde a -> a
sürece tip olarak a
bulunur tür *
(beton türlerinin tür), tip ifadenin sonucu a -> a
olacaktır da sahip tür *
(yani beton türlerinin tür).
Peki, tür ve tip olduğunu Maybe
? Peki, Maybe
başka bir beton tipi elde etmek için beton tipine uygulanabilir. Yani, Maybe
bir alan bir tür düzeyinde fonksiyonu gibi biraz gibi görünüyor türü arasında tür *
ve döner tip bir tür *
. Biz sürdü bir değer seviyesi işlevini olsaydı değeri arasında tip Int
ve döndürülen değer bir tip Int
, biz bunu verecekti tip imzasını Int -> Int
böylece kıyas yoluyla biz vermelidir, Maybe
bir tür imza * -> *
. GHCi kabul eder:
> :kind Maybe
Maybe :: * -> *
Geri dönüyor:
fmap :: Functor f => (a -> b) -> f a -> f b
Bu tip imza olarak, değişken f
tür vardır * -> *
ve değişkenler a
ve b
nazik olması *
; yerleşik operatörün bir ->
tür vardır * -> * -> *
( *
soldan bir tür sağdan ve sağdan bir tür alır ve aynı türden bir tür döndürür *
). Bu ve nazik çıkarsama kurallarına itibaren, olmadığını anlıyoruz a -> b
tür geçerli bir türüdür *
, f a
ve f b
tür geçerli türleri de vardır *
ve (a -> b) -> f a -> f b
türünün geçerli türüdür *
.
Başka bir deyişle, derleyici (a -> b) -> f a -> f b
, doğru türdeki değişkenler için geçerli olduğunu doğrulamak için tür ifadesini "tür kontrolü" yapabilir , doğru türdeki değişkenler için geçerli olduğunu doğrulamak için "tür kontrolleri" yazar sqrt (a**2 + b**2)
.
"Türler" e karşı "türler" için ayrı terimler kullanmanın nedeni (yani "türler" hakkında konuşmamak) çoğunlukla karışıklığı önlemek içindir. Çeşit çok farklı bir görünüm yukarıda tipleri , en azından başlangıçta, ve oldukça farklı davranır gibi görünüyor. (Örneğin, her "normal" tipi aynı tür olduğu fikri etrafında baş sarmak için biraz zaman alır *
ve tür a -> b
olduğu *
değil * -> *
.)
Bunlardan bazıları da tarihseldir. GHC Haskell geliştikçe, değerler, türler ve türler arasındaki farklılıklar bulanıklaşmaya başladı. Bu günlerde değerler türlere "yükseltilebilir" ve türler ve türler gerçekten aynı şeydir. Dolayısıyla, modern Haskell'de değerler hem türlere hem de ARE türlerine (neredeyse) sahiptir ve türlerin türleri sadece daha fazla türlerdir.
@ user21820, "türler ve türler gerçekten aynı şeydir" hakkında ek açıklamalar istedi. Biraz daha açık olmak gerekirse, modern GHC Haskell'de (8.0.1 sürümünden beri, sanırım), türler ve türler derleyici kodunun çoğunda eşit olarak ele alınmaktadır . Derleyici, sırasıyla bir değerin türü veya bir türün türü hakkında şikayet edip etmediğine bağlı olarak, "türler" ile "türler" arasında ayrım yapmak için bazı hatalar yapar.
Ayrıca, hiçbir uzantı etkinleştirilmemişse, yüzey dilinde kolayca ayırt edilebilirler. Örneğin, türlerin (değerlerin) sözdiziminde bir temsili vardır (örneğin, tür imzalarında), ancak türlerin (türlerinde) - bence - tamamen örtüktür ve göründükleri yerde açık bir sözdizimi yoktur.
Ancak uygun uzantıları açarsanız, türler ve türler arasındaki fark büyük ölçüde ortadan kalkar. Örneğin:
{-# LANGUAGE GADTs, TypeInType #-}
data Foo where
Bar :: Bool -> * -> Foo
İşte, Bar
(hem bir değer hem de) bir türdür. Bir tür olarak Bool -> * -> Foo
, bir tür tür alan Bool
(tür, aynı zamanda tür olan) ve tür tür alan *
ve tür tür üreten tür düzeyinde bir işlevdir Foo
. Yani:
type MyBar = Bar True Int
doğru kontroller.
@AndrejBauer'ın cevabında açıkladığı gibi, türler ve türler arasında ayrım yapmanın başarısızlığı güvensizdir - *
türünün / türünün kendisi (modern Haskell'deki gibi) paradokslara yol açan bir tür / tür olması. Bununla birlikte, Haskell'in tür sistemi sonlandırılmadığı için zaten paradokslarla doludur, bu yüzden büyük bir sorun olarak kabul edilmez.