表达非评价

时间:2017-12-23 16:53:29

标签: agda dependent-type

我试图在没有延迟构造函数的情况下定义CoList。我遇到了一个问题,我使用with表达式,但agda没有细化子类型的类型。

module Failing where

open import Data.Unit
open import Data.Empty
open import Data.Maybe
open import Data.Nat
open import Data.Vec hiding (head ; tail ; map ; take)

record CoList (A : Set) : Set where
  coinductive
  field
    head : Maybe A
    tail : maybe (λ _ → ⊤) ⊥ head -> CoList A
open CoList

nil : ∀ {A} -> CoList A
head nil = nothing
tail nil ()

cons : ∀ {A} -> A -> CoList A -> CoList A
head (cons x xs) = just x
tail (cons x xs) tt = xs

take : ∀ {A} -> CoList A -> (n : ℕ) -> Maybe (Vec A n)
take l zero = just []
take l (suc n) with head l
...                 | nothing = nothing
...                 | just x = map (λ xs → x ∷ xs) (take (tail l {!!}) n)

该洞的类型是maybe (λ _ → ⊤) ⊥ (head l),但由于带有表达式,我希望该类型为。我希望这是因为我在head l并且在那种情况下使用了head l = just x。如果我尝试使用tt agda模式填充整体,则会出现以下错误:

⊤ !=< (maybe (λ _ → ⊤) ⊥ (head l)) of type Set
when checking that the expression tt has type
(maybe (λ _ → ⊤) ⊥ (head l))

我回答了下面的问题,所以现在我很好奇是否有更好的方法来编码此列表而没有延迟构造函数?

2 个答案:

答案 0 :(得分:3)

在函数参数和目标的类型中,您可以将with t视为替换t与您匹配的任何内容。但是,当您执行head l时,with不会出现在您的目标类型中 - 一旦您部分构建了解决方案,其类型涉及head l的目标只会在稍后出现。这就是您的初始尝试不起作用的原因。

如你的答案所示,inspect成语确实是解决此类问题的常用方法。

对于具有“多个构造函数”的共同类型的编码,我知道有两种(密切相关的)方法:

  1. 互感/共感类型:

    data   CoList′ (A : Set) : Set
    record CoList  (A : Set) : Set
    
    data CoList′ A where
      [] : CoList′ A
      _∷_ : A → CoList A → CoList′ A
    
    record CoList A where
      coinductive
      field
        unfold : CoList′ A
    
    open CoList
    
    repeat : ∀ {A} → A → CoList A
    repeat x .unfold = x ∷ repeat x
    
    take : ∀ {A} → ℕ → CoList A → List A
    take zero    _ = []
    take (suc n) xs with unfold xs
    ... | [] = []
    ... | x ∷ xs′ = x ∷ take n xs′
    
  2. 明确地使用cofixpoint:

    data CoList′ (A : Set) (CoList : Set) : Set where
      [] : CoList′ A CoList
      _∷_ : A → CoList → CoList′ A CoList
    
    record CoList (A : Set) : Set where
      coinductive
      field
        unfold : CoList′ A (CoList A)
    
    open CoList
    
    repeat : ∀ {A} → A → CoList A
    repeat x .unfold = x ∷ repeat x
    
    take : ∀ {A} → ℕ → CoList A → List A
    take zero    _ = []
    take (suc n) xs with unfold xs
    ... | [] = []
    ... | x ∷ xs′ = x ∷ take n xs′
    

答案 1 :(得分:2)

我找到的一个解决方案是使用检查习语。显然,在agda的抽象中,不要传播平等。 inspect成语使得平等显而易见。

data Uncons (A : Set) : Set where
  Nil : Uncons A
  Cons : A -> CoList A -> Uncons A

uncons : ∀ {A} -> CoList A -> Uncons A
uncons l with head l | inspect head l
uncons l | nothing   | _ = Nil
uncons l | just x    | [ p ] = Cons x (tail l (subst (maybe (λ _ -> ⊤) ⊥) (sym p) tt))

take : ∀ {A} -> CoList A -> (n : ℕ) -> Maybe (Vec A n)
take l zero = just []
take l (suc n) with uncons l
...               | Nil = nothing
...               | Cons x xs = map (λ rest → x ∷ rest) (take xs n)