16

Agda manuel:Neden inductive datatypes, 'tür Bad A = C (Bad a -> a) `gibi türlerin yasaklanmasını önler. <a href="http://wiki.portal.chalmers.se/agda/agda.php?n=ReferenceManual.InductiveDataTypesAndPatternMatching">Inductive Data Types and Pattern Matching</a> durumlarına

normalleşmesini sağlamak için, endüktif oluşumları kesinlikle olumlu pozisyonlarda yer almalıdır. Örneğin, aşağıdaki veri türü izin verilmez:

data Bad : Set where 
    bad : (Bad → Bad) → Bad 

yapıcısına argüman Bad olumsuz bir olay olmadığı için.

Bu gereksinim neden tümleşik veri türleri için gereklidir?

cevap

14

veri türü özeldir Biz sonsuz döngü yapabilirsiniz.

data Bad : Set where 
    bad : (Bad → Bad) → Bad 

unbad : Bad → (Bad → Bad) 
unbad (bad f) = f 

Bakalım nasıl. (Agda içinde olmasa) Biz tip Bad ait Agda şartlarını türsüz lambda hesabı terimlerinden bir çeviri [[e]] tanımlayabilirsiniz

e := x | \x. e | e e' 

: Hatırlama, türsüz lambda hesabı bu terimleri vardır Şimdi

[[x]]  = x 
[[\x. e]] = bad (\x -> [[e]]) 
[[e e']] = unbad [[e]] [[e']] 

sen Bad tipinde sonlandırılmamış bir terim oluşturmak için favori olmayan sonlandırılmamış yazılan lambda terimini kullanabilir. Örneğin, aşağıda tip Bad olmayan sonlandırma ifadeye (\x. x x) (\x. x x) çevirmek olabilir: türü bu argüman için özellikle uygun bir form oldu rağmen

unbad (bad (\x -> unbad x x)) (bad (\x -> unbad x x)) 

, herhangi bir işin biraz genelleştirilebilir Yinelemeli yinelemeli veri türü.

+1

Güzel cevap. Bu zarif yaklaşımı, teorik açıklamasından (yazılmamış lambda hesabı) gömdüm. Söz konusu dile keyfi bir özendirme yapması için onu genişletmek mümkün olabilir mi (Agda hadi söyleyelim)? –

+4

@ PetrPudlák Öyleyse, ben daha iyi tip teorisyenler benden daha uzakta olan memurlarımla sohbet ettim. Mutabakat, bu 'Kötü' bir tür terime sebep olmazdı. a '(gerçekten önemsediğin şey budur; özyineleme, sadece oraya ulaşmaktır). Tartışma şöyle olurdu: Bir dizi kuramsal model olan Agda kurabilirsiniz; o zaman bu modele bir tek eleman kümesi olarak "Bad" in bir yorumunu ekleyebilirsin; sonuçta ortaya çıkan modelde hala ıssız türler olduğu için, 'Bad' terimlerini başka türdeki döngü koşullarına çeviren hiçbir işlev yoktur. –

11

Örnek vermek gerekirse, böyle bir veri türünün herhangi bir türden birinde oturmamıza izin verdiği örnek Turner, D.A. (2004-07-28), Total Functional Programming, tarikat. 3.1, sayfa 758 yılında Kural 2: Tip tekrarlama eşdeğişkin olmalıdır kötü 'özyinelemeli veri türü

data Bad a = C (Bad a -> a) 
"

Biz başlayacağız en Haskell kullanarak daha ayrıntılı bir örnek yapalım.'.

ve yineleme diğer herhangi bir şekilde olmadan ondan Y combinator oluştururlar. Bu tür bir veri türü olan yineleme herhangi bir yapı ya da sonsuz bir yineleme ile her tür yaşayan bize izin verdiği anlamına gelir.

Türlenmemiş lambda Diferensiyel

The Y combinator bu anahtarı, x x kendisi için x geçerli olduğunu

Y = λf.(λx.f (x x)) (λx.f (x x)) 

olarak tanımlanır. Yazılan dillerde, bu doğrudan mümkün değildir, çünkü geçerli bir x türü olabilir. Ama Bad veri türü bu modülo yapıcısı ekleme/kaldırma sağlar:

selfApp :: Bad a -> a 
selfApp ([email protected](C x')) = x' x 

, biz onun yapıcı paketini ve kendisi x için içeri işlevini uygulayabilirsiniz x :: Bad a almak. Biz bunun nasıl öğrendiğinizde, Y bağdaştırıcının inşa etmek kolaydır: ne selfApp ne de yc özyinelemeli olduğunu

yc :: (a -> a) -> a 
yc f = let fxx = C (\x -> f (selfApp x)) -- this is the λx.f (x x) part of Y 
     in selfApp fxx 

Not, kendisine bir fonksiyonun hiçbir özyinelemeli çağrı var. Özyineleme sadece özyinelemeli veri türümüzde görünür.

Yapılı birleştiricinin gerçekte ne yapması gerektiğini kontrol edebiliriz. en GCD diyelim

loop :: a 
loop = yc id 

veya hesaplamak: o türsüz lambda hesabının bir gömme olması ile Verdiğin

gcd' :: Int -> Int -> Int 
gcd' = yc gcd0 
    where 
    gcd0 :: (Int -> Int -> Int) -> (Int -> Int -> Int) 
    gcd0 rec a b | c == 0  = b 
        | otherwise = rec b c 
     where c = a `mod` b