Skip to content

Commit d33553e

Browse files
committed
Compile if_then_else_ expressions
1 parent 8ad5f09 commit d33553e

File tree

6 files changed

+136
-20
lines changed

6 files changed

+136
-20
lines changed

Main.hs

+38-5
Original file line numberDiff line numberDiff line change
@@ -110,12 +110,25 @@ isOp (Hs.UnQual _ Hs.Symbol{}) = True
110110
isOp (Hs.Special _ Hs.Cons{}) = True
111111
isOp _ = False
112112

113+
freshString :: String -> TCM String
114+
freshString s = do
115+
ctx <- getContextNames
116+
-- prettyShow <$> freshName_ s
117+
-- ^ this returns 'x' even when context contains 'x'??
118+
return $ freshWrt (show <$> ctx) s
119+
where
120+
freshWrt :: [String] -> String -> String
121+
freshWrt xs s
122+
| s `elem` xs = freshWrt xs (s ++ "'")
123+
| otherwise = s
124+
113125
-- Builtins ---------------------------------------------------------------
114126

115127
data Prim = Unit
116128
| Nat | Float | Word64
117129
| Char
118130
| List | Cons | Nil
131+
| Bool | True_ | False_
119132
deriving (Show, Eq)
120133

121134
type Builtins = Map QName Prim
@@ -125,6 +138,7 @@ getBuiltins = Map.fromList . concat <$> mapM getB
125138
[ builtinUnit |-> Unit
126139
, builtinNat |-> Nat, builtinFloat |-> Float
127140
, builtinWord64 |-> Word64
141+
, builtinBool |-> Bool, builtinTrue |-> True_, builtinFalse |-> False_
128142
, builtinChar |-> Char
129143
, builtinList |-> List , builtinCons |-> Cons , builtinNil |-> Nil
130144
]
@@ -142,6 +156,9 @@ compilePrim = \case
142156
Nat -> unqual "Integer"
143157
Float -> unqual "Double"
144158
Word64 -> unqual "Word64"
159+
Bool -> unqual "Bool"
160+
True_ -> unqual "True"
161+
False_ -> unqual "False"
145162
Char -> unqual "Char"
146163
List -> special Hs.ListCon
147164
Cons -> special Hs.Cons
@@ -241,7 +258,11 @@ compileTerm :: Builtins -> Term -> TCM (Hs.Exp ())
241258
compileTerm builtins v =
242259
case unSpine v of
243260
Var x es -> (`app` es) . Hs.Var () . Hs.UnQual () . hsName =<< showTCM (Var x [])
244-
Def f es -> (`app` es) . Hs.Var () =<< hsQName builtins f
261+
Def f es
262+
| show (qnameName f) == "if_then_else_"
263+
-> ite es
264+
| otherwise
265+
-> (`app` es) . Hs.Var () =<< hsQName builtins f
245266
Con h i es -> (`app` es) . Hs.Con () =<< hsQName builtins (conName h)
246267
Lit (LitNat _ n) -> return $ Hs.intE n
247268
Lit (LitFloat _ d) -> return $ Hs.Lit () $ Hs.Frac () (toRational d) (show d)
@@ -251,11 +272,23 @@ compileTerm builtins v =
251272
Lam _ b -> underAbstraction_ b (compileTerm builtins)
252273
t -> genericDocError =<< text "bad term:" <?> prettyTCM t
253274
where
254-
app :: Hs.Exp () -> Elims -> TCM (Hs.Exp ())
255-
app hd es = do
275+
compileArgs :: Elims -> TCM [Hs.Exp ()]
276+
compileArgs es = do
256277
let Just args = allApplyElims es
257-
args <- mapM (compileTerm builtins . unArg) $ filter visible args
258-
return $ eApp hd args
278+
mapM (compileTerm builtins . unArg) $ filter visible args
279+
280+
app :: Hs.Exp () -> Elims -> TCM (Hs.Exp ())
281+
app hd es = eApp <$> pure hd <*> compileArgs es
282+
283+
ite :: Elims -> TCM (Hs.Exp ())
284+
ite es = compileArgs es >>= \case
285+
-- fully applied
286+
(b : t : f : es') -> return $ Hs.If () b t f `eApp` es'
287+
-- partially applied -> eta-expand
288+
es' -> do
289+
xs <- fmap Hs.name . drop (length es') <$> mapM freshString ["b", "t", "f"]
290+
let [b, t, f] = es' ++ (Hs.var <$> xs)
291+
return $ Hs.lamE (Hs.pvar <$> xs) $ Hs.If () b t f
259292

260293
compilePats :: Builtins -> NAPs -> TCM [Hs.Pat ()]
261294
compilePats builtins ps = mapM (compilePat builtins . namedArg) $ filter visible ps

Prelude.agda

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
module Prelude where
2+
3+
open import Agda.Builtin.List public
4+
open import Agda.Builtin.Nat public
5+
open import Agda.Builtin.Bool public
6+
open import Agda.Builtin.Float public
7+
open import Agda.Builtin.Word public
8+
open import Agda.Builtin.Char public
9+
open import Agda.Builtin.Equality public
10+
11+
variable
12+
a b c d e f g h i j k l m n o p q r s t u v w x y z : Set
13+
14+
infix 0 if_then_else_
15+
if_then_else_ : Bool a a a
16+
if true then t else f = t
17+
if false then t else f = f

README.md

-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ See test/Test.agda for an example.
66

77
### Future work
88

9-
- Compile if/then/else
109
- Literals in patterns
1110
- Map instance arguments to Haskell type classes (definitions and use) [#3](https://github.com/agda/agda2hs/pull/3)
1211
- `where` clauses

test/Prelude.agda

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
module Prelude where
2+
3+
open import Agda.Builtin.List public
4+
open import Agda.Builtin.Nat public
5+
open import Agda.Builtin.Bool public
6+
open import Agda.Builtin.Float public
7+
open import Agda.Builtin.Word public
8+
open import Agda.Builtin.Char public
9+
open import Agda.Builtin.Equality public
10+
11+
variable
12+
a b c d e f g h i j k l m n o p q r s t u v w x y z : Set
13+
14+
infix 0 if_then_else_
15+
if_then_else_ : Bool a a a
16+
if true then t else f = t
17+
if false then t else f = f

test/Test.agda

+38-12
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,6 @@
11
module _ where
22

3-
open import Agda.Builtin.List
4-
open import Agda.Builtin.Nat
5-
open import Agda.Builtin.Float
6-
open import Agda.Builtin.Word
7-
open import Agda.Builtin.Char
8-
open import Agda.Builtin.Equality
9-
10-
variable
11-
a b : Set
3+
open import Prelude
124

135
-- ** Foreign HS code
146

@@ -78,9 +70,9 @@ ex_char = 'a'
7870
postulate
7971
toEnum : Nat Char
8072

81-
d : Char
82-
d = toEnum 100
83-
{-# COMPILE AGDA2HS d #-}
73+
char_d : Char
74+
char_d = toEnum 100
75+
{-# COMPILE AGDA2HS char_d #-}
8476

8577
-- ** Polymorphic functions
8678

@@ -113,3 +105,37 @@ assoc (suc a) b c rewrite assoc a b c = refl
113105
thm : xs ys sum (xs ++ ys) ≡ sum xs + sum ys
114106
thm [] ys = refl
115107
thm (x ∷ xs) ys rewrite thm xs ys | assoc x (sum xs) (sum ys) = refl
108+
109+
-- ** Booleans
110+
111+
ex_bool : Bool
112+
ex_bool = true
113+
{-# COMPILE AGDA2HS ex_bool #-}
114+
115+
ex_if : Nat
116+
ex_if = if true then 1 else 0
117+
{-# COMPILE AGDA2HS ex_if #-}
118+
119+
if_over : Nat
120+
if_over = (if true then (λ x x) else (λ x x + 1)) 0
121+
{-# COMPILE AGDA2HS if_over #-}
122+
123+
if_partial₁ : List Nat List Nat
124+
if_partial₁ = map (if true then 1 else_)
125+
{-# COMPILE AGDA2HS if_partial₁ #-}
126+
127+
if_partial₂ : List Nat List (Nat Nat)
128+
if_partial₂ = map (if true then_else_)
129+
{-# COMPILE AGDA2HS if_partial₂ #-}
130+
131+
if_partial₃ : List Bool List (Nat Nat Nat)
132+
if_partial₃ = map if_then_else_
133+
{-# COMPILE AGDA2HS if_partial₃ #-}
134+
135+
if_partial₄ : List Bool List (Nat Nat)
136+
if_partial₄ = map (if_then 1 else_)
137+
{-# COMPILE AGDA2HS if_partial₄ #-}
138+
139+
if_partial₅ : Bool Nat List Nat List Nat
140+
if_partial₅ b f = map (if b then f else_)
141+
{-# COMPILE AGDA2HS if_partial₅ #-}

test/golden/Test.hs

+26-2
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,8 @@ ex_word = fromInteger 0
3838
ex_char :: Char
3939
ex_char = 'a'
4040

41-
d :: Char
42-
d = toEnum 100
41+
char_d :: Char
42+
char_d = toEnum 100
4343

4444
(++) :: [a] -> [a] -> [a]
4545
[] ++ ys = ys
@@ -55,3 +55,27 @@ plus3 = map (\ n -> n + 3)
5555
doubleLambda :: Integer -> Integer -> Integer
5656
doubleLambda = \ a b -> a + 2 * b
5757

58+
ex_bool :: Bool
59+
ex_bool = True
60+
61+
ex_if :: Integer
62+
ex_if = if True then 1 else 0
63+
64+
if_over :: Integer
65+
if_over = (if True then \ x -> x else \ x -> x + 1) 0
66+
67+
if_partial₁ :: [Integer] -> [Integer]
68+
if_partial₁ = map (\ f -> if True then 1 else f)
69+
70+
if_partial₂ :: [Integer] -> [Integer -> Integer]
71+
if_partial₂ = map (\ t f -> if True then t else f)
72+
73+
if_partial₃ :: [Bool] -> [Integer -> Integer -> Integer]
74+
if_partial₃ = map (\ b t f -> if b then t else f)
75+
76+
if_partial₄ :: [Bool] -> [Integer -> Integer]
77+
if_partial₄ = map (\ section f -> if section then 1 else f)
78+
79+
if_partial₅ :: Bool -> Integer -> [Integer] -> [Integer]
80+
if_partial₅ b f = map (\ f' -> if b then f else f')
81+

0 commit comments

Comments
 (0)