我正在尝试实现一种类型,该类型表示无限二叉树上的(可能)无限路径。当前,该定义类似于stdlib中的Conat。
open import Size
open import Codata.Thunk
data BinaryTreePath (i : Size) : Set where
here : BinaryTreePath i
branchL : Thunk BinaryTreePath i → BinaryTreePath i
branchR : Thunk BinaryTreePath i → BinaryTreePath i
zero : ∀ {i} → BinaryTreePath i
zero = branchL λ where .force → zero
infinity : ∀ {i} → BinaryTreePath i
infinity = branchR λ where .force → infinity
现在我想定义一个具有更长重复部分的值,例如LRRL。我现在能写的最好的是以下内容(很快就会变得乏味)。
sqrt2 : ∀ {i} → BinaryTreePath i
sqrt2 =
branchL λ where .force → branchR λ where .force → branchR λ where .force → branchL λ where .force → sqrt2
-- or --
sqrt2 : ∀ {i} → BinaryTreePath i
sqrt2 = branchL λ where
.force → branchR λ where
.force → branchR λ where
.force → branchL λ where
.force → sqrt2
定义branchL'
和branchR'
,以便以下通过类型检查和终止检查。
sqrt2 : ∀ {i} → BinaryTreePath i
sqrt2 = branchL' (branchR' (branchR' (branchL' sqrt2)))
在常规函数中包装零件不起作用:
branchL' : (∀ {i} → BinaryTreePath i) → (∀ {j} → BinaryTreePath j)
branchL' path = branchL λ where .force → path
zero' : ∀ {i} → BinaryTreePath i
zero' = branchL' zero'
-- ^^^^^ Termination checking failed
因此,我尝试将其包装到宏中,但是当branchL λ where .force → path
作为path
给出时,我找不到如何构造术语Term
的方法。以下内容也不起作用:
open import Agda.Builtin.Reflection
open import Data.Unit
open import Data.List
macro
branchL' : Term → Term → TC ⊤
branchL' v hole = do
path ← unquoteTC v
term ← quoteTC (branchL λ where .force → path)
-- ^^^^ error
unify hole term
{- error message:
Cannot instantiate the metavariable _32 to solution BinaryTreePath
.j since it contains the variable .j which is not in scope of the
metavariable or irrelevant in the metavariable but relevant in the
solution
when checking that the expression path' has type BinaryTreePath .j
-}
答案 0 :(得分:4)
我建议不要模仿branchL'
和branchR'
,而是建议模仿我们的工作
在Codata.Stream
中定义一个循环的展开?
关键思想是我们可以定义辅助函数,这些辅助函数在其中使用Thunk
类型并因此确保他们以受保护的方式使用其参数。
第一步是定义一种Choice
人可以制作的小语言,然后赋予它
BinaryTreePath
中的语义:
data Choice : Set where
L R : Choice
choice : ∀ {i} → Choice → Thunk BinaryTreePath i → BinaryTreePath i
choice L t = branchL t
choice R t = branchR t
然后我们可以提升这种语义,使其不仅适用于个人选择,而且适用于 选择列表:
open import Data.List
_<|_ : ∀ {i} → List Choice → BinaryTreePath i → BinaryTreePath i
[] <| t = t
(c ∷ cs) <| t = choice c (λ where .force → cs <| t)
现在到了关键时刻:如果我们有一个非空的选择列表,我们就会知道 静态地说,它将导致的路径将受到保护。
open import Data.List.NonEmpty
_⁺<|_ : ∀ {i} → List⁺ Choice → Thunk BinaryTreePath i → BinaryTreePath i
(c ∷ cs) ⁺<| t = choice c (λ where .force → cs <| t .force)
使用此组合器,我们可以无缝定义cycle
:
cycle : ∀ {i} → List⁺ Choice → BinaryTreePath i
cycle cs = cs ⁺<| (λ where .force → cycle cs)
然后使用循环直接获得您的示例:
sqrt2 : ∀ {i} → BinaryTreePath i
sqrt2 = cycle (L ∷ R ∷ R ∷ L ∷ [])
我已将代码放在self-contained gist中。