{-# OPTIONS_GHC -Wall -Werror #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeApplications #-}
module Documentation.SBV.Examples.ADT.Types where
import Data.SBV
data M = Var { M -> String
var :: String }
| Lam { M -> String
bound :: String
, M -> M
body :: M
}
| App { M -> M
fn :: M
, M -> M
arg :: M
}
data T = TInt
| TStr
| TArr { T -> T
dom :: T, T -> T
rng :: T }
mkSymbolic [''M]
mkSymbolic [''T]
env :: SString -> ST
env :: SBV String -> ST
env = String -> SBV String -> ST
forall a. SMTDefinable a => String -> a
uninterpret String
"env"
typeOf :: SM -> ST
typeOf :: SBV M -> ST
typeOf = String -> SBV M -> ST
forall a. SMTDefinable a => String -> a
uninterpret String
"typeOf"
tc :: SM -> ST -> SBool
tc :: SBV M -> ST -> SBool
tc = String -> (SBV M -> ST -> SBool) -> SBV M -> ST -> SBool
forall a.
(SMTDefinable a, Typeable a, Lambda Symbolic a) =>
String -> a -> a
smtFunction String
"constraints" ((SBV M -> ST -> SBool) -> SBV M -> ST -> SBool)
-> (SBV M -> ST -> SBool) -> SBV M -> ST -> SBool
forall a b. (a -> b) -> a -> b
$ \SBV M
m ST
t ->
[sCase|M m of
-- Var case. The environment must match the type we expect.
Var s -> env s .== t
-- Abstraction case. Type must be a function, whose domain matches the variable.
-- And body much match the range. Note that we can't do a nested scase
-- here, unfortunately, since custom quasi-quoters do not nest.
Lam v b
| isTArr t .&& env v .== sdom t
-> tc b (srng t)
-- Application case. In this case, we ask the solver to give us the type of the
-- function, and then ensure the whole thing is well-formedvx
App f a -> let tf = typeOf f
in isTArr tf -- f must have an arrow type
.&& tc f tf -- The function must type-check with that type
.&& tc a (sdom tf) -- Argument must have the type of this function
.&& t .== srng tf -- Final result must match the type we're looking for
-- Otherwise, ill-typed.
_ -> sFalse
|]
wellTyped :: SM -> SBool
wellTyped :: SBV M -> SBool
wellTyped SBV M
m = SBV M -> ST -> SBool
tc SBV M
m (SBV M -> ST
typeOf SBV M
m)
idWF :: IO SatResult
idWF :: IO SatResult
idWF = SBool -> IO SatResult
forall a. Satisfiable a => a -> IO SatResult
sat (SBool -> IO SatResult) -> SBool -> IO SatResult
forall a b. (a -> b) -> a -> b
$ SBV M -> SBool
wellTyped (SBV M -> SBool) -> SBV M -> SBool
forall a b. (a -> b) -> a -> b
$ SBV String -> SBV M -> SBV M
sLam SBV String
x SBV M
vx
where x :: SBV String
x = String -> SBV String
forall a. SymVal a => a -> SBV a
literal String
"x"
vx :: SBV M
vx = SBV String -> SBV M
sVar SBV String
x
intFuncAppString :: IO SatResult
intFuncAppString :: IO SatResult
intFuncAppString = SymbolicT IO SBool -> IO SatResult
forall a. Satisfiable a => a -> IO SatResult
sat (SymbolicT IO SBool -> IO SatResult)
-> SymbolicT IO SBool -> IO SatResult
forall a b. (a -> b) -> a -> b
$ do
SBV M
plus1 <- String -> Symbolic (SBV M)
forall a. SymVal a => String -> Symbolic (SBV a)
free String
"plus1"
SBool -> SymbolicT IO ()
forall a. QuantifiedBool a => a -> SymbolicT IO ()
forall (m :: * -> *) a.
(SolverContext m, QuantifiedBool a) =>
a -> m ()
constrain (SBool -> SymbolicT IO ()) -> SBool -> SymbolicT IO ()
forall a b. (a -> b) -> a -> b
$ SBV M -> ST -> SBool
tc SBV M
plus1 (T -> ST
forall a. SymVal a => a -> SBV a
literal (T
TInt T -> T -> T
`TArr` T
TInt))
SBV M
str <- String -> Symbolic (SBV M)
forall a. SymVal a => String -> Symbolic (SBV a)
free String
"str"
SBool -> SymbolicT IO ()
forall a. QuantifiedBool a => a -> SymbolicT IO ()
forall (m :: * -> *) a.
(SolverContext m, QuantifiedBool a) =>
a -> m ()
constrain (SBool -> SymbolicT IO ()) -> SBool -> SymbolicT IO ()
forall a b. (a -> b) -> a -> b
$ SBV M -> ST -> SBool
tc SBV M
str ST
sTStr
SBool -> SymbolicT IO SBool
forall a. a -> SymbolicT IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (SBool -> SymbolicT IO SBool) -> SBool -> SymbolicT IO SBool
forall a b. (a -> b) -> a -> b
$ SBV M -> SBool
wellTyped (SBV M -> SBool) -> SBV M -> SBool
forall a b. (a -> b) -> a -> b
$ SBV M -> SBV M -> SBV M
sApp SBV M
plus1 SBV M
str
selfAppNotWellTyped :: IO SatResult
selfAppNotWellTyped :: IO SatResult
selfAppNotWellTyped = SBool -> IO SatResult
forall a. Satisfiable a => a -> IO SatResult
sat (SBool -> IO SatResult) -> SBool -> IO SatResult
forall a b. (a -> b) -> a -> b
$ SBV M -> SBool
wellTyped (SBV M -> SBool) -> SBV M -> SBool
forall a b. (a -> b) -> a -> b
$ SBV String -> SBV M -> SBV M
sLam SBV String
x (SBV M -> SBV M -> SBV M
sApp SBV M
vx SBV M
vx)
where x :: SBV String
x = String -> SBV String
forall a. SymVal a => a -> SBV a
literal String
"x"
vx :: SBV M
vx = SBV String -> SBV M
sVar SBV String
x