2014-01-18 12 views
7

Da alle Agda Programme beenden, wird die Evaluierungsstrategie nicht für denotational Semantik Rolle, aber es ist von Bedeutung für die Leistung (falls Sie jemals Ihre Agda Programme laufen).Wird die Bewertungsstrategie von Agda irgendwo angegeben?

Also, welche Bewertungsstrategie nicht verwendet Agda? Verwendet die Verwendung von Codata (♯, ♭) anstelle von Daten die Bewertungsstrategie? Gibt es eine Möglichkeit, Call-by-Need als "faule" Bewertung zu erzwingen?

Antwort

10

Typüberprüfung könnte Auswertung Normalform erfordern, so dass es nicht egal, auch wenn Sie nicht über Ihre Programme laufen (aber ja, Auswertung bei der Typprüfung als die Ausführung des Programms angesehen werden könnte). Agda wertet Ausdrücke in normaler Reihenfolge aus, was bedeutet, dass Funktionen angewendet werden, bevor ihre Argumente ausgewertet werden. Datentypen werden auch nur bei Bedarf ausgewertet.

Angenommen, ich habe diese Definition der natürlichen Zahlen und einige Operationen auf sie:

data ℕ : Set where 
    zero : ℕ 
    suc : ℕ → ℕ 

{-# BUILTIN NATURAL ℕ #-} 
-- Older Agda versions might require you to specify 
-- what is zero and what is suc. 

infixl 4 _+_ 
infixl 5 _*_ 
infixr 6 _^_ 

_+_ : (m n : ℕ) → ℕ 
zero + n = n 
suc m + n = suc (m + n) 

_*_ : (m n : ℕ) → ℕ 
zero * n = zero 
suc m * n = n + m * n 

_^_ : (m n : ℕ) → ℕ 
m^zero = suc zero 
m^suc n = m * m^n 

Da wir mit einstelligen Zahlen arbeiten, 2^16 Auswertung wird eine ganze Menge Zeit in Anspruch nehmen. Wenn wir jedoch versuchen, const 1 (2^16) auszuwerten, wird es in fast keiner Zeit fertig sein.

const : ∀ {a b} {A : Set a} {B : Set b} → 
    A → B → A 
const x _ = x 

Das gleiche gilt für die Datentypen:

infixr 3 _∷_ 

data List {a} (A : Set a) : Set a where 
    [] : List A 
    _∷_ : A → List A → List A 

record ⊤ {ℓ} : Set ℓ where 

Head : ∀ {a} {A : Set a} → List A → Set _ 
Head   []  = ⊤ 
Head {A = A} (_ ∷ _) = A 

head : ∀ {a} {A : Set a} (xs : List A) → Head xs 
head []  = _ 
head (x ∷ _) = x 

replicate : ∀ {a} {A : Set a} → ℕ → A → List A 
replicate 0  _ = [] 
replicate (suc n) x = x ∷ replicate n x 

Wieder head (replicate 1000000 1) fast sofort auswerten wird.

jedoch normale Ordnung nicht ist Call-by-Bedarf, sind nämlich Berechnungen nicht mit anderen geteilt.

open import Data.Product 
open import Relation.Binary.PropositionalEquality 

slow : 2^16 ≡ 65536 
slow = refl 

slower₁ : (λ x → x , x) (2^16) ≡ (65536 , 65536) 
slower₁ = refl 

slower₂ : 
    let x : ℕ 
     x = 2^16 
    in _≡_ {A = ℕ × ℕ} (x , x) (65536 , 65536) 
slower₂ = refl 

In diesem Fall geben Sie slower₁ und slower₂ Überprüfung wird in etwa der doppelten Zeit slow Bedürfnisse nehmen. Im Vergleich dazu Call-by-Bedarf würde die Berechnung von x teilen und 2^16 nur einmal berechnen.


Beachten Sie, dass Sie bei der Typprüfung Ausdrücke in Normalform auswerten müssen. Wenn es irgendwelche Bindemittel sind um (λ oder Π), müssen Sie unter dem Bindemittel gehen und den inneren Ausdruck als auch zu bewerten.

λ n → 1 + n ==> λ n → suc n 

Wie funktioniert CODATA das Bild ändern? Die Interaktion mit der Reduktion ist eigentlich recht einfach: ♯ x wertet nicht weiter, wenn Sie für sie gelten.

Dies ist auch, warum als Verzögerung und als Kraft bekannt ist.


Sie können Agda auch zu Haskell kompilieren. Es gibt auch JavaScript, aber ich weiß nicht, wie das kompiliert wird, also bleibe ich bei der Kompilation zu Haskell.

Die Strategie Auswertung ist vor allem, was das Haskell Compiler verwendet.Als Beispiel ist hier, was zu den folgenden Definitionen passiert:

data ℕ : Set where 
    zero : ℕ 
    suc : ℕ → ℕ 

_+_ : (m n : ℕ) → ℕ 
zero + n = n 
suc m + n = suc (m + n) 

data Vec {a} (A : Set a) : ℕ → Set a where 
    [] : Vec A zero 
    _∷_ : ∀ {n} → A → Vec A n → Vec A (suc n) 

Und nach der Kompilierung:

-- ℕ 
data T1 a0 = C2 
      | C3 a0 

-- Vec 
data T12 a0 a1 a2 = C15 
        | C17 a0 a1 a2 

-- _+_ 
d6 (C2) v0 = MAlonzo.RTE.mazCoerce v0 
d6 v0 v1 
    = MAlonzo.RTE.mazCoerce 
     (d_1_6 (MAlonzo.RTE.mazCoerce v0) (MAlonzo.RTE.mazCoerce v1)) 
    where d_1_6 (C3 v0) v1 
     = MAlonzo.RTE.mazCoerce 
      (C3 
      (MAlonzo.RTE.mazCoerce 
       (d6 (MAlonzo.RTE.mazCoerce v0) (MAlonzo.RTE.mazCoerce v1)))) 

Yup, ist die letzte ein bisschen verrückt. Aber wenn Sie ein bisschen squit, können Sie sehen:

d6 C2 v0 = v0 
d6 (C3 v0) v1 = C3 (d6 v0 v1) 
Verwandte Themen