~ubuntu-branches/ubuntu/raring/agda/raring-proposed

« back to all changes in this revision

Viewing changes to src/full/Agda/TypeChecking/Primitive.hs

  • Committer: Bazaar Package Importer
  • Author(s): Iain Lane
  • Date: 2009-07-20 19:49:41 UTC
  • Revision ID: james.westby@ubuntu.com-20090720194941-hcjy91vrn16csh7d
Tags: upstream-2.2.4+dfsg
ImportĀ upstreamĀ versionĀ 2.2.4+dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
{-# LANGUAGE CPP, FlexibleInstances, UndecidableInstances,
 
2
             GeneralizedNewtypeDeriving, ScopedTypeVariables
 
3
  #-}
 
4
 
 
5
{-| Primitive functions, such as addition on builtin integers.
 
6
-}
 
7
module Agda.TypeChecking.Primitive where
 
8
 
 
9
import Control.Monad
 
10
import Data.Map (Map)
 
11
import qualified Data.Map as Map
 
12
import Data.Char
 
13
 
 
14
import Agda.Syntax.Position
 
15
import Agda.Syntax.Common hiding (Nat)
 
16
import Agda.Syntax.Internal
 
17
import Agda.Syntax.Literal
 
18
import Agda.Syntax.Concrete.Pretty ()
 
19
import Agda.Syntax.Abstract.Name
 
20
import qualified Agda.Syntax.Concrete.Name as C
 
21
 
 
22
import Agda.TypeChecking.Monad
 
23
import Agda.TypeChecking.Monad.Builtin
 
24
import Agda.TypeChecking.Reduce
 
25
import Agda.TypeChecking.Substitute
 
26
import Agda.TypeChecking.Errors
 
27
import Agda.TypeChecking.Pretty ()  -- instances only
 
28
 
 
29
import Agda.Utils.Monad
 
30
import Agda.Utils.Pretty (pretty)
 
31
 
 
32
#include "../undefined.h"
 
33
import Agda.Utils.Impossible
 
34
 
 
35
-- | Rewrite a literal to constructor form if possible.
 
36
constructorForm :: MonadTCM tcm => Term -> tcm Term
 
37
constructorForm v@(Lit (LitInt r n))
 
38
    | n == 0    = primZero
 
39
    | n > 0     = do
 
40
        s <- primSuc
 
41
        return $ s `apply` [Arg NotHidden $ Lit $ LitInt r $ n - 1]
 
42
    | otherwise = return v
 
43
constructorForm v = return v
 
44
 
 
45
---------------------------------------------------------------------------
 
46
-- * Primitive functions
 
47
---------------------------------------------------------------------------
 
48
 
 
49
data PrimitiveImpl = PrimImpl Type PrimFun
 
50
 
 
51
-- Haskell type to Agda type
 
52
 
 
53
newtype Str = Str { unStr :: String }
 
54
    deriving (Eq, Ord)
 
55
 
 
56
newtype Nat = Nat { unNat :: Integer }
 
57
    deriving (Eq, Ord, Num, Integral, Enum, Real)
 
58
 
 
59
instance Show Nat where
 
60
    show = show . unNat
 
61
 
 
62
class PrimType a where
 
63
    primType :: MonadTCM tcm => a -> tcm Type
 
64
 
 
65
instance (PrimType a, PrimType b) => PrimTerm (a -> b) where
 
66
    primTerm _ = unEl <$> (primType (undefined :: a) --> primType (undefined :: b))
 
67
 
 
68
instance PrimTerm a => PrimType a where
 
69
    primType _ = el $ primTerm (undefined :: a)
 
70
 
 
71
class    PrimTerm a       where primTerm :: MonadTCM tcm => a -> tcm Term
 
72
instance PrimTerm Integer where primTerm _ = primInteger
 
73
instance PrimTerm Bool    where primTerm _ = primBool
 
74
instance PrimTerm Char    where primTerm _ = primChar
 
75
instance PrimTerm Double  where primTerm _ = primFloat
 
76
instance PrimTerm Str     where primTerm _ = primString
 
77
instance PrimTerm Nat     where primTerm _ = primNat
 
78
 
 
79
instance PrimTerm a => PrimTerm [a] where
 
80
    primTerm _ = list (primTerm (undefined :: a))
 
81
 
 
82
instance PrimTerm a => PrimTerm (IO a) where
 
83
    primTerm _ = io (primTerm (undefined :: a))
 
84
 
 
85
-- From Agda term to Haskell value
 
86
 
 
87
class ToTerm a where
 
88
    toTerm :: MonadTCM tcm => tcm (a -> Term)
 
89
 
 
90
instance ToTerm Integer where toTerm = return $ Lit . LitInt noRange
 
91
instance ToTerm Nat     where toTerm = return $ Lit . LitInt noRange . unNat
 
92
instance ToTerm Double  where toTerm = return $ Lit . LitFloat noRange
 
93
instance ToTerm Char    where toTerm = return $ Lit . LitChar noRange
 
94
instance ToTerm Str     where toTerm = return $ Lit . LitString noRange . unStr
 
95
 
 
96
instance ToTerm Bool where
 
97
    toTerm = do
 
98
        true  <- primTrue
 
99
        false <- primFalse
 
100
        return $ \b -> if b then true else false
 
101
 
 
102
-- | @buildList A ts@ builds a list of type @List A@. Assumes that the terms
 
103
--   @ts@ all have type @A@.
 
104
buildList :: MonadTCM tcm => Term -> tcm ([Term] -> Term)
 
105
buildList a = do
 
106
    nil'  <- primNil
 
107
    cons' <- primCons
 
108
    let nil       = nil'  `apply` [Arg Hidden a]
 
109
        cons x xs = cons' `apply` [Arg Hidden a, Arg NotHidden x, Arg NotHidden xs]
 
110
    return $ foldr cons nil
 
111
 
 
112
instance (PrimTerm a, ToTerm a) => ToTerm [a] where
 
113
    toTerm = do
 
114
        a      <- primTerm (undefined :: a)
 
115
        mkList <- buildList a
 
116
        fromA  <- toTerm
 
117
        return $ mkList . map fromA
 
118
 
 
119
-- From Haskell value to Agda term
 
120
 
 
121
type FromTermFunction a = Arg Term -> TCM (Reduced (Arg Term) a)
 
122
 
 
123
class FromTerm a where
 
124
    fromTerm :: MonadTCM tcm => tcm (FromTermFunction a)
 
125
 
 
126
instance FromTerm Integer where
 
127
    fromTerm = fromLiteral $ \l -> case l of
 
128
        LitInt _ n -> Just n
 
129
        _          -> Nothing
 
130
 
 
131
instance FromTerm Nat where
 
132
    fromTerm = fromLiteral $ \l -> case l of
 
133
        LitInt _ n -> Just $ Nat n
 
134
        _          -> Nothing
 
135
 
 
136
instance FromTerm Double where
 
137
    fromTerm = fromLiteral $ \l -> case l of
 
138
        LitFloat _ x -> Just x
 
139
        _            -> Nothing
 
140
 
 
141
instance FromTerm Char where
 
142
    fromTerm = fromLiteral $ \l -> case l of
 
143
        LitChar _ c -> Just c
 
144
        _           -> Nothing
 
145
 
 
146
instance FromTerm Str where
 
147
    fromTerm = fromLiteral $ \l -> case l of
 
148
        LitString _ s -> Just $ Str s
 
149
        _             -> Nothing
 
150
 
 
151
instance FromTerm Bool where
 
152
    fromTerm = do
 
153
        true  <- primTrue
 
154
        false <- primFalse
 
155
        fromReducedTerm $ \t -> case t of
 
156
            _   | t === true  -> Just True
 
157
                | t === false -> Just False
 
158
                | otherwise   -> Nothing
 
159
        where
 
160
            Def x [] === Def y []   = x == y
 
161
            Con x [] === Con y []   = x == y
 
162
            Var n [] === Var m []   = n == m
 
163
            _        === _          = False
 
164
 
 
165
instance (ToTerm a, FromTerm a) => FromTerm [a] where
 
166
    fromTerm = do
 
167
        nil'  <- primNil
 
168
        cons' <- primCons
 
169
        nil   <- isCon nil'
 
170
        cons  <- isCon cons'
 
171
        toA   <- fromTerm
 
172
        fromA <- toTerm
 
173
        return $ mkList nil cons toA fromA
 
174
        where
 
175
            isCon (Lam _ b) = isCon $ absBody b
 
176
            isCon (Con c _) = return c
 
177
            isCon v         = do
 
178
                d <- prettyTCM v
 
179
                typeError $ GenericError $ "expected constructor in built-in binding to " ++ show d
 
180
                                -- TODO: check this when binding the things
 
181
 
 
182
            mkList nil cons toA fromA t = do
 
183
                t <- reduce t
 
184
                let arg = Arg (argHiding t)
 
185
                case unArg t of
 
186
                    Con c []
 
187
                        | c == nil  -> return $ YesReduction []
 
188
                    Con c [x,xs]
 
189
                        | c == cons ->
 
190
                            redBind (toA x)
 
191
                                (\x' -> arg $ Con c [x',xs]) $ \y ->
 
192
                            redBind
 
193
                                (mkList nil cons toA fromA xs)
 
194
                                (\xs' -> arg $ Con c [Arg NotHidden $ fromA y, xs']) $ \ys ->
 
195
                            redReturn (y : ys)
 
196
                    _ -> return $ NoReduction t
 
197
 
 
198
-- | Conceptually: @redBind m f k = either (return . Left . f) k =<< m@
 
199
redBind :: MonadTCM tcm => tcm (Reduced a a') -> (a -> b) ->
 
200
             (a' -> tcm (Reduced b b')) -> tcm (Reduced b b')
 
201
redBind ma f k = do
 
202
    r <- ma
 
203
    case r of
 
204
        NoReduction x   -> return $ NoReduction $ f x
 
205
        YesReduction y  -> k y
 
206
 
 
207
redReturn :: MonadTCM tcm => a -> tcm (Reduced a' a)
 
208
redReturn = return . YesReduction
 
209
 
 
210
fromReducedTerm :: MonadTCM tcm => (Term -> Maybe a) -> tcm (FromTermFunction a)
 
211
fromReducedTerm f = return $ \t -> do
 
212
    t <- reduce t
 
213
    case f $ unArg t of
 
214
        Just x  -> return $ YesReduction x
 
215
        Nothing -> return $ NoReduction t
 
216
 
 
217
fromLiteral :: MonadTCM tcm => (Literal -> Maybe a) -> tcm (FromTermFunction a)
 
218
fromLiteral f = fromReducedTerm $ \t -> case t of
 
219
    Lit lit -> f lit
 
220
    _       -> Nothing
 
221
 
 
222
-- Tying the knot
 
223
mkPrimFun1 :: (MonadTCM tcm, PrimType a, PrimType b, FromTerm a, ToTerm b) =>
 
224
              (a -> b) -> tcm PrimitiveImpl
 
225
mkPrimFun1 f = do
 
226
    toA   <- fromTerm
 
227
    fromB <- toTerm
 
228
    t     <- primType f
 
229
    return $ PrimImpl t $ PrimFun __IMPOSSIBLE__ 1 $ \[v] -> liftTCM $
 
230
        redBind (toA v)
 
231
            (\v' -> [v']) $ \x ->
 
232
        redReturn $ fromB $ f x
 
233
 
 
234
mkPrimFun2 :: (MonadTCM tcm, PrimType a, PrimType b, PrimType c, FromTerm a, ToTerm a, FromTerm b, ToTerm c) =>
 
235
              (a -> b -> c) -> tcm PrimitiveImpl
 
236
mkPrimFun2 f = do
 
237
    toA   <- fromTerm
 
238
    fromA <- toTerm
 
239
    toB   <- fromTerm
 
240
    fromC <- toTerm
 
241
    t     <- primType f
 
242
    return $ PrimImpl t $ PrimFun __IMPOSSIBLE__ 2 $ \[v,w] -> liftTCM $
 
243
        redBind (toA v)
 
244
            (\v' -> [v',w]) $ \x ->
 
245
        redBind (toB w)
 
246
            (\w' -> [Arg (argHiding v) (fromA x), w']) $ \y ->
 
247
        redReturn $ fromC $ f x y
 
248
 
 
249
mkPrimFun4 :: ( MonadTCM tcm
 
250
              , PrimType a, FromTerm a, ToTerm a
 
251
              , PrimType b, FromTerm b, ToTerm b
 
252
              , PrimType c, FromTerm c, ToTerm c
 
253
              , PrimType d, FromTerm d
 
254
              , PrimType e, ToTerm e) =>
 
255
              (a -> b -> c -> d -> e) -> tcm PrimitiveImpl
 
256
mkPrimFun4 f = do
 
257
    (toA, fromA) <- (,) <$> fromTerm <*> toTerm
 
258
    (toB, fromB) <- (,) <$> fromTerm <*> toTerm
 
259
    (toC, fromC) <- (,) <$> fromTerm <*> toTerm
 
260
    toD          <- fromTerm
 
261
    fromE        <- toTerm
 
262
    t <- primType f
 
263
    return $ PrimImpl t $ PrimFun __IMPOSSIBLE__ 4 $ \[a,b,c,d] -> liftTCM $
 
264
        redBind (toA a)
 
265
            (\a' -> [a',b,c,d]) $ \x ->
 
266
        redBind (toB b)
 
267
            (\b' -> [Arg (argHiding a) (fromA x), b', c, d]) $ \y ->
 
268
        redBind (toC c)
 
269
            (\c' -> [ Arg (argHiding a) (fromA x)
 
270
                    , Arg (argHiding b) (fromB y), c', d]) $ \z ->
 
271
        redBind (toD d)
 
272
            (\d' -> [ Arg (argHiding a) (fromA x)
 
273
                    , Arg (argHiding b) (fromB y)
 
274
                    , Arg (argHiding c) (fromC z)
 
275
                    , d']) $ \w ->
 
276
        redReturn $ fromE $ f x y z w
 
277
 
 
278
-- Abstract primitive functions
 
279
abstractPrim :: (MonadTCM tcm, PrimType a) => a -> tcm PrimitiveImpl
 
280
abstractPrim x = abstractFromType (primType x)
 
281
 
 
282
abstractFromType :: MonadTCM tcm => tcm Type -> tcm PrimitiveImpl
 
283
abstractFromType mt = do
 
284
    t <- mt
 
285
    return $ PrimImpl t $ PrimFun __IMPOSSIBLE__ (arity t) $ \args -> NoReduction <$> normalise args
 
286
 
 
287
-- Type combinators
 
288
infixr 4 -->
 
289
 
 
290
(-->) :: MonadTCM tcm => tcm Type -> tcm Type -> tcm Type
 
291
a --> b = do
 
292
    a' <- a
 
293
    b' <- b
 
294
    return $ El (getSort a' `sLub` getSort b') $ Fun (Arg NotHidden a') b'
 
295
 
 
296
gpi :: MonadTCM tcm => Hiding -> String -> tcm Type -> tcm Type -> tcm Type
 
297
gpi h name a b = do
 
298
    a' <- a
 
299
    x  <- freshName_ name
 
300
    b' <- addCtx x (Arg h a') b
 
301
    return $ El (getSort a' `sLub` getSort b') $ Pi (Arg h a') (Abs name b')
 
302
 
 
303
hPi, nPi :: MonadTCM tcm => String -> tcm Type -> tcm Type -> tcm Type
 
304
hPi = gpi Hidden
 
305
nPi = gpi NotHidden
 
306
 
 
307
var :: MonadTCM tcm => Integer -> tcm Term
 
308
var n = return $ Var n []
 
309
 
 
310
infixl 9 <@>, <#>
 
311
 
 
312
gApply :: MonadTCM tcm => Hiding -> tcm Term -> tcm Term -> tcm Term
 
313
gApply h a b = do
 
314
    x <- a
 
315
    y <- b
 
316
    return $ x `apply` [Arg h y]
 
317
 
 
318
(<@>),(<#>) :: MonadTCM tcm => tcm Term -> tcm Term -> tcm Term
 
319
(<@>) = gApply NotHidden
 
320
(<#>) = gApply Hidden
 
321
 
 
322
list :: MonadTCM tcm => tcm Term -> tcm Term
 
323
list t = primList <@> t
 
324
 
 
325
io :: MonadTCM tcm => tcm Term -> tcm Term
 
326
io t = primIO <@> t
 
327
 
 
328
el :: MonadTCM tcm => tcm Term -> tcm Type
 
329
el t = El (Type 0) <$> t
 
330
 
 
331
tset :: MonadTCM tcm => tcm Type
 
332
tset = return $ sort (Type 0)
 
333
 
 
334
---------------------------------------------------------------------------
 
335
-- * The actual primitive functions
 
336
---------------------------------------------------------------------------
 
337
 
 
338
type Op   a = a -> a -> a
 
339
type Fun  a = a -> a
 
340
type Rel  a = a -> a -> Bool
 
341
type Pred a = a -> Bool
 
342
 
 
343
primitiveFunctions :: Map String (TCM PrimitiveImpl)
 
344
primitiveFunctions = Map.fromList
 
345
 
 
346
    -- Integer functions
 
347
    [ "primIntegerPlus"     |-> mkPrimFun2 ((+)        :: Op Integer)
 
348
    , "primIntegerMinus"    |-> mkPrimFun2 ((-)        :: Op Integer)
 
349
    , "primIntegerTimes"    |-> mkPrimFun2 ((*)        :: Op Integer)
 
350
    , "primIntegerDiv"      |-> mkPrimFun2 (div        :: Op Integer)    -- partial
 
351
    , "primIntegerMod"      |-> mkPrimFun2 (mod        :: Op Integer)    -- partial
 
352
    , "primIntegerEquality" |-> mkPrimFun2 ((==)       :: Rel Integer)
 
353
    , "primIntegerLess"     |-> mkPrimFun2 ((<)        :: Rel Integer)
 
354
    , "primIntegerAbs"      |-> mkPrimFun1 (Nat . abs  :: Integer -> Nat)
 
355
    , "primNatToInteger"    |-> mkPrimFun1 (unNat      :: Nat -> Integer)
 
356
    , "primShowInteger"     |-> mkPrimFun1 (Str . show :: Integer -> Str)
 
357
 
 
358
    -- Natural number functions
 
359
    , "primNatPlus"         |-> mkPrimFun2 ((+)                     :: Op Nat)
 
360
    , "primNatMinus"        |-> mkPrimFun2 ((\x y -> max 0 (x - y)) :: Op Nat)
 
361
    , "primNatTimes"        |-> mkPrimFun2 ((*)                     :: Op Nat)
 
362
    , "primNatDivSucAux"    |-> mkPrimFun4 ((\k m n j -> k + div (n + m - j) (m + 1)) :: Nat -> Nat -> Nat -> Nat -> Nat)
 
363
    , "primNatModSucAux"    |->
 
364
        let aux :: Nat -> Nat -> Nat -> Nat -> Nat
 
365
            aux k m n j | n > j     = mod (n - j - 1) (m + 1)
 
366
                        | otherwise = k + n
 
367
        in mkPrimFun4 aux
 
368
    , "primNatEquality"     |-> mkPrimFun2 ((==)                    :: Rel Nat)
 
369
    , "primNatLess"         |-> mkPrimFun2 ((<)                     :: Rel Nat)
 
370
 
 
371
    -- Floating point functions
 
372
    , "primIntegerToFloat"  |-> mkPrimFun1 (fromIntegral :: Integer -> Double)
 
373
    , "primFloatPlus"       |-> mkPrimFun2 ((+)          :: Op Double)
 
374
    , "primFloatMinus"      |-> mkPrimFun2 ((-)          :: Op Double)
 
375
    , "primFloatTimes"      |-> mkPrimFun2 ((*)          :: Op Double)
 
376
    , "primFloatDiv"        |-> mkPrimFun2 ((/)          :: Op Double)
 
377
    , "primFloatLess"       |-> mkPrimFun2 ((<)          :: Rel Double)
 
378
    , "primRound"           |-> mkPrimFun1 (round        :: Double -> Integer)
 
379
    , "primFloor"           |-> mkPrimFun1 (floor        :: Double -> Integer)
 
380
    , "primCeiling"         |-> mkPrimFun1 (ceiling      :: Double -> Integer)
 
381
    , "primExp"             |-> mkPrimFun1 (exp          :: Fun Double)
 
382
    , "primLog"             |-> mkPrimFun1 (log          :: Fun Double)    -- partial
 
383
    , "primSin"             |-> mkPrimFun1 (sin          :: Fun Double)
 
384
    , "primShowFloat"       |-> mkPrimFun1 (Str . show   :: Double -> Str)
 
385
 
 
386
    -- Character functions
 
387
    , "primCharEquality"    |-> mkPrimFun2 ((==) :: Rel Char)
 
388
    , "primIsLower"         |-> mkPrimFun1 isLower
 
389
    , "primIsDigit"         |-> mkPrimFun1 isDigit
 
390
    , "primIsAlpha"         |-> mkPrimFun1 isAlpha
 
391
    , "primIsSpace"         |-> mkPrimFun1 isSpace
 
392
    , "primIsAscii"         |-> mkPrimFun1 isAscii
 
393
    , "primIsLatin1"        |-> mkPrimFun1 isLatin1
 
394
    , "primIsPrint"         |-> mkPrimFun1 isPrint
 
395
    , "primIsHexDigit"      |-> mkPrimFun1 isHexDigit
 
396
    , "primToUpper"         |-> mkPrimFun1 toUpper
 
397
    , "primToLower"         |-> mkPrimFun1 toLower
 
398
    , "primCharToNat"       |-> mkPrimFun1 (fromIntegral . fromEnum :: Char -> Nat)
 
399
    , "primNatToChar"       |-> mkPrimFun1 (toEnum . fromIntegral   :: Nat -> Char)
 
400
    , "primShowChar"        |-> mkPrimFun1 (Str . show . pretty . LitChar noRange)
 
401
 
 
402
    -- String functions
 
403
    , "primStringToList"    |-> mkPrimFun1 unStr
 
404
    , "primStringFromList"  |-> mkPrimFun1 Str
 
405
    , "primStringAppend"    |-> mkPrimFun2 (\s1 s2 -> Str $ unStr s1 ++ unStr s2)
 
406
    , "primStringEquality"  |-> mkPrimFun2 ((==) :: Rel Str)
 
407
    , "primShowString"      |-> mkPrimFun1 (Str . show . pretty . LitString noRange . unStr)
 
408
    ]
 
409
    where
 
410
        (|->) = (,)
 
411
 
 
412
lookupPrimitiveFunction :: MonadTCM tcm => String -> tcm PrimitiveImpl
 
413
lookupPrimitiveFunction x =
 
414
    case Map.lookup x primitiveFunctions of
 
415
        Just p  -> liftTCM p
 
416
        Nothing -> typeError $ NoSuchPrimitiveFunction x
 
417
 
 
418
-- | Rebind a primitive. Assumes everything is type correct. Used when
 
419
--   importing a module with primitives.
 
420
rebindPrimitive :: MonadTCM tcm => String -> tcm PrimFun
 
421
rebindPrimitive x = do
 
422
    PrimImpl _ pf <- lookupPrimitiveFunction x
 
423
    bindPrimitive x pf
 
424
    return pf
 
425