Skip to content

Commit c5106ec

Browse files
authored
Merge branch 'master' into data-map
2 parents 3294ffb + c4b26e2 commit c5106ec

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

85 files changed

+2106
-989
lines changed

.github/workflows/ci.yml

-2
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,8 @@ jobs:
2323
os: [ubuntu-latest] # macOS-latest, windows-latest
2424
cabal: ["3.8"]
2525
ghc:
26-
- "8.6.5"
2726
- "8.8.4"
2827
- "8.10.7"
29-
- "9.0.2"
3028
- "9.2.5"
3129
- "9.4.3"
3230
- "9.6.3"

README.md

+8-34
Original file line numberDiff line numberDiff line change
@@ -2,40 +2,14 @@
22

33
# agda2hs
44

5-
Agda2hs is a tool for producing verified and readable Haskell code by
6-
extracting it from a (lightly annotated) Agda program. For example,
7-
the following Agda program encodes well-formed binary search trees:
8-
9-
```agda
10-
open import Haskell.Prelude
11-
12-
_≤_ : {{Ord a}} → a → a → Set
13-
x ≤ y = (x <= y) ≡ True
14-
15-
data BST (a : Set) {{@0 _ : Ord a}} (@0 lower upper : a) : Set where
16-
Leaf : (@0 pf : lower ≤ upper) → BST a lower upper
17-
Node : (x : a) (l : BST a lower x) (r : BST a x upper) → BST a lower upper
18-
19-
{-# COMPILE AGDA2HS BST #-}
20-
```
21-
22-
agda2hs translates this to the following Haskell datatype:
23-
24-
```haskell
25-
module BST where
26-
27-
data BST a = Leaf
28-
| Node a (BST a) (BST a)
29-
```
30-
31-
## Objective
32-
33-
The goal of this project is *not* to translate arbitrary Agda code to Haskell.
34-
Rather it is to carve out a common sublanguage between Agda and Haskell,
35-
with a straightforward translation from the Agda side to the Haskell side.
36-
This lets you write your program in the Agda fragment, using full Agda
37-
to prove properties about it, and then translate it to nice looking readable
38-
Haskell code that you can show your Haskell colleagues without shame.
5+
Agda2hs is a tool for producing verified and readable Haskell code by extracting
6+
it from a (lightly annotated) Agda program. The goal of this project is *not* to
7+
translate arbitrary Agda code to Haskell. Rather it is to carve out a common
8+
sublanguage between Agda and Haskell, with a straightforward translation from
9+
the Agda side to the Haskell side. This lets you write your program in the Agda
10+
fragment, using full Agda to prove properties about it, and then translate it to
11+
nice looking readable Haskell code that you can show your Haskell colleagues
12+
without shame.
3913

4014
## Documentation
4115

agda2hs.cabal

+21-15
Original file line numberDiff line numberDiff line change
@@ -52,32 +52,38 @@ executable agda2hs
5252
Agda2Hs.Compile.TypeDefinition,
5353
Agda2Hs.Compile.Types,
5454
Agda2Hs.Compile.Utils,
55+
Agda2Hs.Compile.Var,
5556
Agda2Hs.Config,
5657
Agda2Hs.HsUtils,
5758
Agda2Hs.Pragma,
5859
Agda2Hs.Render,
5960
AgdaInternals,
6061
Paths_agda2hs
6162
autogen-modules: Paths_agda2hs
62-
build-depends: base >= 4.10 && < 4.20,
63-
Agda >= 2.6.4 && < 2.6.5,
64-
bytestring >= 0.11.5 && < 0.13,
65-
containers >= 0.6 && < 0.8,
66-
unordered-containers >= 0.2.19 && < 0.3,
67-
mtl >= 2.2.2 && < 2.4,
68-
directory >= 1.2.6.2 && < 1.4,
69-
filepath >= 1.4.1.0 && < 1.5,
70-
haskell-src-exts >= 1.23 && < 1.25,
71-
syb >= 0.7.2 && < 0.8,
72-
text >= 2.0.2 && < 2.2,
73-
deepseq >= 1.4.4 && < 1.6,
74-
yaml >= 0.11 && < 0.12,
75-
aeson >= 2.2 && < 2.3,
63+
build-depends: base >= 4.13 && < 4.20,
64+
Agda >= 2.6.4 && < 2.6.5,
65+
bytestring >= 0.11.5 && < 0.13,
66+
containers >= 0.6 && < 0.8,
67+
unordered-containers >= 0.2.19 && < 0.3,
68+
mtl >= 2.2 && < 2.3 || >= 2.3.1,
69+
transformers >= 0.6 && < 0.7,
70+
monad-control >= 1.0 && < 1.1,
71+
directory >= 1.2.6.2 && < 1.4,
72+
filepath >= 1.4.1.0 && < 1.5,
73+
haskell-src-exts >= 1.23 && < 1.25,
74+
syb >= 0.7.2 && < 0.8,
75+
text >= 2.0.2 && < 2.2,
76+
deepseq >= 1.4.4 && < 1.6,
77+
yaml >= 0.11 && < 0.12,
78+
aeson >= 2.2 && < 2.3,
7679
default-language: Haskell2010
7780
default-extensions: LambdaCase
7881
RecordWildCards
7982
FlexibleContexts
8083
MultiWayIf
8184
TupleSections
8285
ScopedTypeVariables
83-
ghc-options: -Werror
86+
ViewPatterns
87+
NamedFieldPuns
88+
PatternSynonyms
89+
ghc-options: -Werror -rtsopts

cabal.project

+2
Original file line numberDiff line numberDiff line change
@@ -1 +1,3 @@
11
packages: ./agda2hs.cabal
2+
constraints: Agda +debug
3+

docs/source/index.md

+67
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,72 @@
11
# agda2hs Documentation
22

3+
`agda2hs` is a tool for producing verified and readable Haskell code by
4+
extracting it from a (lightly annotated) Agda program. For example,
5+
the following Agda program encodes well-formed binary search trees:
6+
7+
```agda
8+
open import Haskell.Prelude
9+
10+
_≤_ : {{Ord a}} → a → a → Set
11+
x ≤ y = (x <= y) ≡ True
12+
13+
data BST (a : Set) {{@0 _ : Ord a}} (@0 lower upper : a) : Set where
14+
Leaf : (@0 pf : lower ≤ upper) → BST a lower upper
15+
Node : (x : a) (l : BST a lower x) (r : BST a x upper) → BST a lower upper
16+
17+
{-# COMPILE AGDA2HS BST #-}
18+
```
19+
20+
agda2hs translates this to the following Haskell datatype:
21+
22+
```haskell
23+
module BST where
24+
25+
data BST a = Leaf
26+
| Node a (BST a) (BST a)
27+
```
28+
29+
`agda2hs` is intended to be used together with the provided `Haskell.Prelude`
30+
module, which provides an Agda implementation of (a large subset of) the Haskell
31+
Prelude. It also provides proofs for reasoning about Haskell functions under the
32+
`Haskell.Law` namespace. `agda2hs` is *not* compatible with other Agda libraries
33+
such as the Agda standard library.
34+
35+
## Objective
36+
37+
The goal of this project is *not* to translate arbitrary Agda code to Haskell.
38+
Rather it is to carve out a common sublanguage between Agda and Haskell,
39+
with a straightforward translation from the Agda side to the Haskell side.
40+
This lets you write your program in the Agda fragment, using full Agda
41+
to prove properties about it, and then translate it to nice looking readable
42+
Haskell code that you can show your Haskell colleagues without shame.
43+
44+
If you want to compile arbitrary Agda programs to runnable (but not readable)
45+
Haskell, you should instead use the built-in
46+
[GHC backend of Agda](https://agda.readthedocs.io/en/v2.6.4/tools/compilers.html#ghc-backend)
47+
(a.k.a. MAlonzo).
48+
49+
## Documentation
50+
51+
The documentation you are currently reading is a work in progress, so if you
52+
have been using `agda2hs` and want to contribute in some way, adding
53+
documentation or examples would be very welcome.
54+
55+
agda2hs was introduced in the Haskell Symposium '22 paper [Reasonable Agda is
56+
Correct Haskell: Writing Verified Haskell using
57+
agda2hs](https://jesper.sikanda.be/files/reasonable-agda-is-correct-haskell.pdf).
58+
59+
## Future work
60+
61+
Currently `agda2hs` is under active development, please take a look at the
62+
[issue tracker](https://github.com/agda/agda2hs/issues). If you have a
63+
suggestion for a new feature that is not yet on the issue tracker, you are
64+
welcome to create a new issue or a PR. Feature requests should be of the form
65+
"Add support for Haskell feature X", *not* "Add support for Agda feature Y" (see
66+
"Objective" above). If you want to compile arbitrary Agda code to Haskell, you
67+
are advised to use Agda's built-in GHC backend instead.
68+
69+
370
```{toctree}
471
---
572
maxdepth: 1

lib/Haskell/Extra/Dec.agda

+4
Original file line numberDiff line numberDiff line change
@@ -41,3 +41,7 @@ mapDec : @0 (a → b)
4141
mapDec f g (True ⟨ x ⟩) = True ⟨ f x ⟩
4242
mapDec f g (False ⟨ h ⟩) = False ⟨ h ∘ g ⟩
4343
{-# COMPILE AGDA2HS mapDec transparent #-}
44+
45+
ifDec : Dec a (@0 {{a}} b) (@0 {{a ⊥}} b) b
46+
ifDec (b ⟨ p ⟩) x y = if b then (λ where {{refl}} x {{p}}) else (λ where {{refl}} y {{p}})
47+
{-# COMPILE AGDA2HS ifDec inline #-}

lib/Haskell/Extra/Delay.agda

+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
{-# OPTIONS --sized-types #-}
2+
3+
module Haskell.Extra.Delay where
4+
5+
open import Agda.Builtin.Size public
6+
7+
open import Haskell.Prelude
8+
open import Haskell.Prim.Thunk
9+
open import Haskell.Extra.Refinement
10+
11+
private variable
12+
x y z : a
13+
@0 i : Size
14+
15+
data Delay (a : Set) (@0 i : Size) : Set where
16+
now : a Delay a i
17+
later : Thunk (Delay a) i Delay a i
18+
19+
data HasResult (x : a) : Delay a i Set where
20+
now : HasResult x (now x)
21+
later : HasResult x (y .force) HasResult x (later y)
22+
23+
runDelay : {@0 x : a} (y : Delay a ∞) @0 HasResult x y a
24+
runDelay (now x) now = x
25+
runDelay (later y) (later p) = runDelay (y .force) p
26+
27+
runDelaySound : {@0 x : a} (y : Delay a ∞) (@0 hr : HasResult x y) runDelay y hr ≡ x
28+
runDelaySound (now x) now = refl
29+
runDelaySound (later y) (later hr) = runDelaySound (y .force) hr
30+
31+
-- tryDelay and unDelay cannot and should not be compiled to Haskell,
32+
-- so they are marked as erased.
33+
@0 tryDelay : (y : Delay a ∞) Nat Maybe (∃ a (λ x HasResult x y))
34+
tryDelay (now x) _ = Just (x ⟨ now ⟩)
35+
tryDelay (later y) zero = Nothing
36+
tryDelay (later y) (suc n) = fmap (mapRefine later) (tryDelay (y .force) n)
37+
38+
@0 unDelay : (y : Delay a ∞) (n : Nat) @0 {IsJust (tryDelay y n)} a
39+
unDelay y n {p} = fromJust (tryDelay y n) {p} .value

lib/Haskell/Extra/Erase.agda

+1
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ module Haskell.Extra.Erase where
4242
instance
4343
rezz-id : {x : a} Rezz a x
4444
rezz-id = rezz _
45+
{-# COMPILE AGDA2HS rezz-id inline #-}
4546

4647
rezzCong : {@0 a : Set} {@0 x : a} (f : a b) Rezz a x Rezz b (f x)
4748
rezzCong f (Rezzed x p) = Rezzed (f x) (cong f p)

lib/Haskell/Extra/Loop.agda

-8
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,6 @@ open import Haskell.Prelude
33

44
module Haskell.Extra.Loop where
55

6-
IsJust : Maybe a Set
7-
IsJust Nothing =
8-
IsJust (Just _) =
9-
10-
fromJust : (x : Maybe a) @0 {IsJust x} a
11-
fromJust (Just x) = x
12-
fromJust Nothing = error "fromJust called on Nothing"
13-
146
data Fuel (f : a Either a b) : (x : Either a b) Set where
157
done : {y} Fuel f (Right y)
168
more : {x} Fuel f (f x) Fuel f (Left x)

lib/Haskell/Extra/Refinement.agda

+14-1
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,23 @@ open import Agda.Primitive
66
private variable
77
ℓ ℓ′ : Level
88

9-
record (@0 a : Set ℓ) (@0 P : a Set ℓ′) : Set (ℓ ⊔ ℓ′) where
9+
record (a : Set ℓ) (@0 P : a Set ℓ′) : Set (ℓ ⊔ ℓ′) where
1010
constructor _⟨_⟩
1111
field
1212
value : a
1313
@0 proof : P value
1414
open public
1515
{-# COMPILE AGDA2HS ∃ unboxed #-}
16+
17+
mapRefine : {@0 P Q : a Set ℓ} (@0 f : {x} P x Q x) ∃ a P ∃ a Q
18+
mapRefine f (x ⟨ p ⟩) = x ⟨ f p ⟩
19+
20+
{-# COMPILE AGDA2HS mapRefine transparent #-}
21+
22+
refineMaybe : {@0 P : a Set ℓ}
23+
(mx : Maybe a) @0 ( {x} mx ≡ Just x P x)
24+
Maybe (∃ a P)
25+
refineMaybe Nothing f = Nothing
26+
refineMaybe (Just x) f = Just (x ⟨ f refl ⟩)
27+
28+
{-# COMPILE AGDA2HS refineMaybe transparent #-}

lib/Haskell/Extra/Sigma.agda

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
module Haskell.Extra.Sigma where
2+
3+
record Σ (a : Set) (b : @0 a Set) : Set where
4+
constructor _,_
5+
field
6+
fst : a
7+
snd : b fst
8+
open Σ public
9+
10+
infix 2 Σ-syntax
11+
12+
Σ-syntax : (a : Set) (@0 a Set) Set
13+
Σ-syntax = Σ
14+
{-# COMPILE AGDA2HS Σ-syntax inline #-}
15+
16+
syntax Σ-syntax a (λ x b) = Σ[ x ∈ a ] b

lib/Haskell/Law.agda

+5
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,18 @@ module Haskell.Law where
33
open import Haskell.Prim
44
open import Haskell.Prim.Bool
55

6+
open import Haskell.Law.Def public
67
open import Haskell.Law.Applicative public
78
open import Haskell.Law.Bool public
9+
open import Haskell.Law.Either public
810
open import Haskell.Law.Eq public
911
open import Haskell.Law.Equality public
1012
open import Haskell.Law.Functor public
13+
open import Haskell.Law.Int public
14+
open import Haskell.Law.Integer public
1115
open import Haskell.Law.List public
1216
open import Haskell.Law.Maybe public
1317
open import Haskell.Law.Monad public
1418
open import Haskell.Law.Monoid public
19+
open import Haskell.Law.Nat public
1520
open import Haskell.Law.Ord public

lib/Haskell/Law/Applicative/List.agda

+5-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,11 @@ private
2222
compositionList : {a b c : Set} (u : List (b c)) (v : List (a b)) (w : List a)
2323
((((pure _∘_) <*> u) <*> v) <*> w) ≡ (u <*> (v <*> w))
2424
compositionList [] _ _ = refl
25-
compositionList us vs ws = trustMe -- TODO
25+
compositionList (u ∷ us) v w
26+
rewrite sym $ concatMap-++-distr (map (u ∘_) v) (((pure _∘_) <*> us) <*> v) (λ f map f w)
27+
| sym $ map-<*>-recomp v w u
28+
| compositionList us v w
29+
= refl
2630

2731
interchangeList : {a b : Set} (u : List (a b)) (y : a)
2832
(u <*> (pure y)) ≡ (pure (_$ y) <*> u)

lib/Haskell/Law/Def.agda

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
module Haskell.Law.Def where
2+
3+
open import Haskell.Prim
4+
5+
Injective : (a b) Set _
6+
Injective f = {x y} f x ≡ f y x ≡ y

lib/Haskell/Law/Either.agda

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
module Haskell.Law.Either where
2+
3+
open import Haskell.Prim
4+
open import Haskell.Prim.Either
5+
6+
open import Haskell.Law.Def
7+
8+
Left-injective : Injective (Left {a}{b})
9+
Left-injective refl = refl
10+
11+
Right-injective : Injective (Right {a}{b})
12+
Right-injective refl = refl

lib/Haskell/Law/Eq.agda

+2-4
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
11
module Haskell.Law.Eq where
22

3-
open import Haskell.Law.Eq.Def public
4-
open import Haskell.Law.Eq.Bool public
5-
open import Haskell.Law.Eq.Maybe public
6-
open import Haskell.Law.Eq.Ordering public
3+
open import Haskell.Law.Eq.Def public
4+
open import Haskell.Law.Eq.Instances public

lib/Haskell/Law/Eq/Bool.agda

-15
This file was deleted.

0 commit comments

Comments
 (0)