Open jwaldmann opened 7 years ago
I agree that the infered type for the expression is a bit overwhelming. Let's break it down:
(MonadResult b ~ e 'IntType, HasMonad b, Embed m e, MatchMonad b m) => [b] -> m (e 'IntType)
(x .+. y) .*. z
is the same as do { tmp <- x .+. y; tmp .*. z }
which makes for much more readable code. But we can easily specialize the signature for SMT expressions:
(Embed m e) => [e IntType] -> m (e IntType)
Backend b => [Expr b IntType] -> SMT b (Expr b IntType)
Hope that helps.
Yes, I would suggest using the signature in item 2 or 3. Unfortunately, I don't know if there is a way to make the infered type signature more understandable.
E.g., in ersatz
(I know it's SAT not SMT, but they also write formulas) you really build terms, and only later interpret them (in whatever monad). So the term (formula) type looks nice and clean. https://hackage.haskell.org/package/ersatz-0.3.1/docs/Ersatz-Bit.html . (I think that's what you had with SMTExpr a
in version 0.3.)
This has the advantage, e.g., that terms that describe numbers can be instances of Num
(so you can use the standard definitions of sum
, etc). Yes, Num
is broken in many ways, but for simple things, it works good enough.
The disadvantage (of working in the Identity monad) is that you need (?) observable sharing for the term type and this looks ugly (e.g., unsafePerformIO (makeStableName' a)
in https://hackage.haskell.org/package/ersatz-0.3.1/docs/src/Ersatz.Problem.html#runSAT ) but it's confined to a library.
"inferred signatures more understandable" - I think if some type synonyms are in scope, ghci will try to use them (to some degree).
Another disadvantage is that you have to keep a representation of all the formulas you're building in memory, basically replicating what your backend is doing. The advantage of the new API is that you can actually use the native expression type of whatever backend you're using as the result type of all SMTLib operations, thus avoiding having to translate back and forth between two representations.
I've built native backends for Z3 and MathSAT (not currently on hackage because they are incomplete) that make use of this fact.
My guess is that the ersatz library is designed to be more of an "specify a problem, send it off to the solver" interface, whereas my library aims for continuous interaction with a solver for example getting interpolants, incremental solving etc.
I adapted a very simple example from smtlib2 version 0.3.1 to 1.0, see https://gitlab.imn.htwk-leipzig.de/waldmann/cp-ws16/commit/d53f037fc7c9a71a63dd6de70369aea9459ec69b
This is all more or less straightforward, but one thing appears really inconvenient to me: types for expressions. Consider this definition:
in 0.3.1. it had type
but now
ghci
tells meWhat!? Is there a shorter notation, perhap some typedefs?