Buna bakmanın birkaç iyi yolu var. Benim için en kolay olan şey “Endüktif” ve “Coinductive tanımları” arasındaki ilişkiyi düşünmektir.
Bir kümenin endüktif bir tanımı bu şekilde gider.
"Nat" kümesi, "Sıfır" Nat konumunda ve n ise Nat ise "Succ n" Nat konumunda ise en küçük set olarak tanımlanır.
Aşağıdaki Ocaml'a karşılık gelir
type nat = Zero | Succ of nat
Bu tanımla ilgili dikkat edilmesi gereken bir nokta, bir sayıdır.
omega = Succ(omega)
bu setin bir üyesi değil. Neden? Diyelim ki, şimdi omega içermeyen hariç, Nat ile aynı öğelere sahip olan N kümesini düşünün. Açıkçası, Sıfır N, ve y N ise, Succ (y) N'dir, ancak N, Nat olandan daha küçüktür ve bu bir çelişkidir. Öyleyse, omega Nat'ta değil.
Veya bir bilgisayar bilimcisi için belki de daha yararlı:
Bazı "a" kümelerine bakıldığında, "a" listesinin "nilüferler Listesi" ndeki en küçük küme olarak tanımlanır ve xs a ve x'in "Cons x xs" de yer alması durumunda listesinde.
Hangi gibi bir şey karşılık gelir
type 'a list = Nil | Cons of 'a * 'a list
Buradaki operatif kelime "en küçük". Eğer "en küçük" dememiş olsaydık, Nat setinin bir muz içerip içermediğini söylemenin bir yolu olmazdı!
Tekrar,
zeros = Cons(Zero,zeros)
bir nat listesi için geçerli bir tanım değildir, tıpkı omega'nın geçerli bir Nat olmadığı gibi.
Tanımlanması verileri bu kullanarak üzerinde çalışmaya işlevleri tanımlamak için bize izin verir gibi indüktif özyinelemeye
let rec plus a b = match a with
| Zero -> b
| Succ(c) -> let r = plus c b in Succ(r)
daha sonra indüksiyon kullanarak (özellikle yapısal indüksiyon) "artı bir Sıfır = a" gibi gerçekleri ispatlayabiliriz.
Kanıtımız a.
Temel durum için Sıfır olalım. plus Zero Zero = match Zero with |Zero -> Zero | Succ(c) -> let r = plus c b in Succ(r)
öyleyse biliyoruz plus Zero Zero = Zero
. a
Bir nat olalım . İndüktif hipotezi varsayalım plus a Zero = a
. Şimdi plus (Succ(a)) Zero = Succ(a)
bunun açıkça belli olduğunu gösteriyoruz. plus (Succ(a)) Zero = match a with |Zero -> Zero | Succ(a) -> let r = plus a Zero in Succ(r) = let r = a in Succ(r) = Succ(a)
Dolayısıyla, doğuştan plus a Zero = a
herkes için indüksiyon yaparak a
.
Elbette daha ilginç şeyler ispatlayabiliriz, ama genel fikir bu.
Şimdiye kadar “en küçük” set olmasını sağlayarak elde ettiğimiz endüktif olarak tanımlanmış verileri ele aldık. Şimdi en büyük küme olmasını sağlayarak elde ettiğimiz ve ortak olarak tanımlanmış kodalarla çalışmak istiyoruz .
Yani
Bir küme olalım. "A Akışı" kümesi, a akışındaki her x için, x, başın bir ve kuyruğunun Akışta olduğu şekilde sıralanan çiftten (kafa, kuyruk) oluşacağı şekilde en büyük küme olarak tanımlanır.
Haskell'de bunu şöyle ifade ederdik:
data Stream a = Stream a (Stream a) --"data" not "newtype"
Aslında, Haskell'de yerleşik listeleri normal bir şekilde kullanıyoruz; bu, düzenli bir çift veya boş bir liste olabilir.
data [a] = [] | a:[a]
Muz da bu tipte bir üye değildir, çünkü sıralı bir çift veya boş liste değildir. Ama şimdi söyleyebiliriz
ones = 1:ones
ve bu tamamen geçerli bir tanımdır. Dahası, bu co-data üzerinde ortak tekrarlar yapabiliriz. Aslında, bir işlevin hem özyinelemeli hem de özyinelemeli olması mümkündür. Özyineleme, verilerden oluşan bir alana sahip olan işlev tarafından tanımlanırken , eşzamanlılık yalnızca eş-veri olan bir ortak etki alanına (aralık olarak da adlandırılır) sahip olduğunu gösterir. İlkel özyineleme, en küçük bazı verilere ulaşana kadar daima daha küçük verilerde "kendini aramak" anlamına geliyordu . İlkel ortak yineleme, daha önce sahip olduklarınızdan büyük veya ona eşit olan veriler üzerinde her zaman "kendini" çağırır.
ones = 1:ones
ilkel olarak ortak özyinelemelidir. İşlev map
(zorunlu dillerdeki "foreach" türüne benzer) hem ilkel olarak özyinelemeli (tür) hem de ilkel olarak özyinelemelidir.
map :: (a -> b) -> [a] -> [b]
map f [] = []
map f (x:xs) = (f x):map f xs
Aynısı zipWith
, bir işlevi ve bir çift listeyi alan ve bu işlevi kullanarak bunları birleştiren işlev için de geçerlidir.
zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]
zipWith f (a:as) (b:bs) = (f a b):zipWith f as bs
zipWith _ _ _ = [] --base case
Klasik fonksiyonel dil örneği Fibonacci dizisidir.
fib 0 = 0
fib 1 = 1
fib n = (fib (n-1)) + (fib (n-2))
ilkel olarak özyinelemeli olan, ancak sonsuz bir liste olarak daha zarif bir şekilde ifade edilebilir
fibs = 0:1:zipWith (+) fibs (tail fibs)
fib' n = fibs !! n --the !! is haskell syntax for index at
ilginç bir indüksiyon / coinduction örneği, bu iki tanımın aynı şeyi hesapladığını kanıtlamaktır. Bu, okuyucu için bir egzersiz olarak bırakılmıştır.