実際、コンパイルエラーがあります。実行可能ファイルはエラーを検出し、そのagda
情報をagda-mode
Emacs に渡します。Emacs は構文の強調表示を行い、エラーがあったことを知らせます。agda
直接使用するとどうなるか見てみましょう。私が使用しているファイルは次のとおりです。
module C1 where
open import Data.Nat
loop : ℕ → ℕ
loop 0 = 0
loop x = loop x
ここで、agda -i../lib-0.7/src -i. C1.agda
(パラメーターは気にしないで-i
ください。実行可能ファイルに標準ライブラリの検索場所を知らせるだけです) を呼び出すと、次のエラーが発生します。
Termination checking failed for the following functions:
loop
Problematic calls:
loop x
(at D:\Agda\tc\C1.agda:7,10-14)
これは確かにコンパイルエラーです。このようなエラーがあるimport
と、このモジュールを他のモジュールからインポートしたり、コンパイルしたりすることができなくなります。たとえば、上記のファイルに次の行を追加するとします。
open import IO
main = run (putStrLn "")
そして、を使用してモジュールをコンパイルすると、次のC-c C-x C-c
ようにagda-mode
文句が言われます。
You can only compile modules without unsolved metavariables
or termination checking problems.
他の種類のコンパイル エラーには、型チェックの問題が含まれます。
module C2 where
open import Data.Bool
open import Data.Nat
type-error : ℕ → Bool
type-error n = n
__________________________
D:\Agda\tc\C2.agda:7,16-17
ℕ !=< Bool of type Set
when checking that the expression n has type Bool
陽性チェックに失敗しました:
module C3 where
data Positivity : Set where
bad : (Positivity → Positivity) → Positivity
__________________________
D:\Agda\tc\C3.agda:3,6-16
Positivity is not strictly positive, because it occurs to the left
of an arrow in the type of the constructor bad in the definition of
Positivity.
または未解決のメタ変数:
module C4 where
open import Data.Nat
meta : ∀ {a} → ℕ
meta = 0
__________________________
Unsolved metas at the following locations:
D:\Agda\tc\C4.agda:5,11-12
ここで、一部のエラーは「行き止まり」であることに気づきましたが、他のエラーはプログラムの作成を続行させてくれます。これは、一部のエラーが他のエラーよりも悪いためです。たとえば、未解決のメタ変数が発生した場合、不足している情報を埋めるだけですべてがうまくいく可能性があります。
agda
コンパイラのハングに関しては、モジュールのチェックまたはコンパイルによってループが発生することはありません。型チェッカーを強制的にループさせてみましょう。モジュールにさらにものを追加しますC1
。
data _≡_ {a} {A : Set a} (x : A) : A → Set a where
refl : x ≡ x
test : loop 1 ≡ 1
test = refl
refl
ここで、それがその型の正しい式であることを確認するには、agda
を評価する必要がありますloop 1
。ただし、終了チェックに失敗したため、は展開されagda
ませんloop
(そして、無限ループに陥ります)。
ただし、C-c C-n
実際agda
には式を評価しようとする必要があるため (基本的には「自分が何をしているのかわかっている」と伝えます)、自然に無限ループに陥ります。
ちなみに、agda
終了チェックを無効にすると、ループを作成できます。
{-# NO_TERMINATION_CHECK #-}
loop : ℕ → ℕ
loop 0 = 0
loop x = loop x
data _≡_ {a} {A : Set a} (x : A) : A → Set a where
refl : x ≡ x
test : loop 1 ≡ 1
test = refl
最終的には次のようになります。
stack overflow
経験則として、agda
コンパイラ プラグマを使用せずにモジュールをチェック (またはコンパイル) してループを作成できる場合、これは実際にはバグであり、バグ トラッカーで報告する必要があります。そうは言っても、コンパイラ プラグマを使用する場合、非終了プログラムを作成する方法はほとんどありません。はすでに見まし{-# NO_TERMINATION_CHECK #-}
たが、他の方法を次に示します。
{-# OPTIONS --no-positivity-check #-}
module Boom where
data Bad (A : Set) : Set where
bad : (Bad A → A) → Bad A
unBad : {A : Set} → Bad A → Bad A → A
unBad (bad f) = f
fix : {A : Set} → (A → A) → A
fix f = (λ x → f (unBad x x)) (bad λ x → f (unBad x x))
loop : {A : Set} → A
loop = fix λ x → x
これは、厳密には正ではないデータ型に依存しています。または、ラッセルのパラドックスagda
を強制的に受け入れSet : Set
て (つまり、Set
isSet
自体の型)、再構築することもできます。
{-# OPTIONS --type-in-type #-}
module Boom where
open import Data.Empty
open import Data.Product
open import Relation.Binary.PropositionalEquality
data M : Set where
m : (I : Set) → (I → M) → M
_∈_ : M → M → Set
a ∈ m I f = Σ I λ i → a ≡ f i
_∉_ : M → M → Set
a ∉ b = (a ∈ b) → ⊥
-- Set of all sets that are not members of themselves.
R : M
R = m (Σ M λ a → a ∉ a) proj₁
-- If a set belongs to R, it does not contain itself.
lem₁ : ∀ {X} → X ∈ R → X ∉ X
lem₁ ((Y , Y∉Y) , refl) = Y∉Y
-- If a set does not contain itself, then it is in R.
lem₂ : ∀ {X} → X ∉ X → X ∈ R
lem₂ X∉X = (_ , X∉X) , refl
-- R does not contain itself.
lem₃ : R ∉ R
lem₃ R∈R = lem₁ R∈R R∈R
-- But R also contains itself - a paradox.
lem₄ : R ∈ R
lem₄ = lem₂ lem₃
loop : {A : Set} → A
loop = ⊥-elim (lem₃ lem₄)
(ソース)。AJC Hurkens によって単純化されたジラールのパラドックスの変形を書くこともできます:
{-# OPTIONS --type-in-type #-}
module Boom where
⊥ = ∀ p → p
¬_ = λ A → A → ⊥
℘_ = λ A → A → Set
℘℘_ = λ A → ℘ ℘ A
U = (X : Set) → (℘℘ X → X) → ℘℘ X
τ : ℘℘ U → U
τ t = λ (X : Set) (f : ℘℘ X → X) (p : ℘ X) → t λ (x : U) → p (f (x X f))
σ : U → ℘℘ U
σ s = s U λ (t : ℘℘ U) → τ t
τσ : U → U
τσ x = τ (σ x)
Δ = λ (y : U) → ¬ (∀ (p : ℘ U) → σ y p → p (τσ y))
Ω = τ λ (p : ℘ U) → ∀ (x : U) → σ x p → p x
loop : (A : Set) → A
loop = (λ (₀ : ∀ (p : ℘ U) → (∀ (x : U) → σ x p → p x) → p Ω) →
(₀ Δ λ (x : U) (₂ : σ x Δ) (₃ : ∀ (p : ℘ U) → σ x p → p (τσ x)) →
(₃ Δ ₂ λ (p : ℘ U) → (₃ λ (y : U) → p (τσ y)))) λ (p : ℘ U) →
₀ λ (y : U) → p (τσ y)) λ (p : ℘ U) (₁ : ∀ (x : U) → σ x p → p x) →
₁ Ω λ (x : U) → ₁ (τσ x)
しかし、これは本当の混乱です。ただし、依存関数のみを使用するという優れた特性があります。奇妙なことに、型チェックを通過することさえできず、agda
ループが発生します。用語全体loop
を 2 つに分割すると役立ちます。