2016-11-21 107 views
2

我想創建一個數據類型交替構造FooBar。有效成員,例如,將是:如何創建只接受其他字段的字段?

Foo (Bar (Foo (Bar End))) 

但不是:

Foo (Foo (Bar End)) 

因爲後者已經連續Foo的。在單一數據聲明中表達這一點的正確方法是什麼?

+0

是否允許'Foo End'? –

+0

@AntonTrunov不......可能是,但是......我只是想知道一般的語法是什麼。 – MaiaVictor

+0

在我的答案中加入了'Foo End'版本。 –

回答

1

一種可能的解決方案是使用一個索引類型:

data FooBarEnd : Nat -> Type where 
    End : FooBarEnd 0 
    Foo : FooBarEnd 1 -> FooBarEnd 0 
    Bar : FooBarEnd 0 -> FooBarEnd 1 

幾個測試:

test1 : FooBarEnd 0 
test1 = Foo (Bar (Foo (Bar End))) 

test2 : FooBarEnd 0 
test2 = End 

test3 : FooBarEnd 1 
test3 = Bar End 

Foo (Foo (Bar End))不是既不FooBarEnd 0,也不FooBarEnd 1的有效期限。

這種方法的缺點是使用指數01的必要性。 我不知道這是否是解決你正在尋找的那種。


如果你決定允許Foo End的有效期,該定義可以改成這樣:

data FooBarEnd : Nat -> Type where 
    End : FooBarEnd 1 
    Foo : {auto prf : n `GTE` 1} -> FooBarEnd n -> FooBarEnd 0 
    Bar : {auto prf : n `LTE` 1} -> FooBarEnd n -> FooBarEnd 2 

GTELTE意味着大於或等於和小於或等於相應。

以上允許Foo End,Bar End等,保留您的原始限制,並且Idris能夠自動推斷隱含證明條款prf

更非正式地,所述(一元)構造Foo預計的類型FooBarEnd 1FooBarEnd 2作爲參數,這意味着我們只允許建Foo EndFoo (Bar ...)的值,因爲我們分離各構造成自己的「亞型」 ,由自然數索引。並且構造函數Bar預計爲End(其索引1 < = 1)或Foo(索引0 < = 1)。

3

有了一個聲明,你需要一個索引類型:

data Foo : Bool -> Type where 
    End : Foo True 
    Bar : Foo True -> Foo False 
    Foo : Foo False -> Foo True 

此具有相同的居民爲以下兩個相互類型:

data FooTrue = End | Foo FooFalse 
data FooFalse = Bar FooTrue 

一般來說,n數據的相互家族類型可表示與由類型與n元素索引的單一類型的家庭。索引表示法的優點是它允許相互類型不可能的泛型操作,因爲可以使用{b : Bool} -> Foo b -> Foo b{b : Bool} -> Foo b -> Foo (not b)等類型進行變換。像長索引列表無限互惠家庭也只能使用索引類型。

+0

有趣的,所以你一定需要另一種數據類型(布爾),對吧?所以,'∀(A:*)。 ∀(B:*)。 ∀(foo:(A - > B))。 ∀(bar:(B - > A))。 ∀(結束:B)。 B'類型,其中包括我所提到的形狀的術語,如'(λfoo.λbar.λend。(foo(bar(foo(bar end))))',並沒有直接表示爲Idris數據類型,是否正確? – MaiaVictor

+2

它有一個表示形式,但它具有'Type 1'類型而不是'Type',這使得它不是非常有用。對於任何可用的Church編碼,我們需要'(∀(A:*).t ):*',也就是一個可預測的'*'系統F具有意想不到的'*',但它不具有依賴性和歸納,Agda/Idris具有歸納性但沒有不可預測性 –

+2

然而,Coq確實有一個選項叫' impredicative-set「,這使得Type的第一級具有可預測性(並將一些消除限制爲更大的類型IIRC),這使得我們可以按照我們喜歡的方式對Church進行編碼。默認情況下,它被禁用,因爲它與經典邏輯不一致,邏輯通常比教會數據更重要。 –

相關問題