Вместо того, чтобы писать branchL'
и branchR'
, могу ли я предложить имитировать то, что мы делаем в Codata.Stream
, чтобы определить развертывание цикла?
Основная идея заключается в том, чтомы можем определить вспомогательные функции, которые используют Thunk
в своем типе, и, таким образом, гарантировать, что они используют свои аргументы в защищенном виде.
Первый шаг - определить небольшой язык из Choice
s, который можно сделатьи дать ему семантику в терминах 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 ∷ [])
Я поместил код в автономную суть.