-
Notifications
You must be signed in to change notification settings - Fork 45
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Possibility of an interface with better ergonomics? #63
Comments
Hi and thanks for starting this discussion again! About 5 months ago I asked the same thing, e.g. building an improved interface layer over the current one. There has been an attempt at this in the past: https://hackage.haskell.org/package/z3-0.3.2/docs/Z3-Lang-Prelude.html As far as I understood it was abandoned because library users preferred to build their own abstractions which directly match their needs. But @IagoAbal told me that he is still open to it. I have not started working on this yet, but would love to. What I was missing so far was my own use case because I am currently not using the library in any projects. If you bring this, I am happy to help with building a higher-layer interface. My perspective on your specific points:
The current API is a minimal wrapper around the C API, so the function names should just be camelCased versions of the original C API functions [1]. In my opinion, having consistent naming with the Z3 documentation is worth more than these prefixes hurt. In a higher layer interface we could definitely choose new names.
I think this is because there isn't much of a Haskell AST, a Haskell AST node is just a wrapped xPlusy <- mkAdd [mkFreshIntVar "x", mkFreshIntVar "y"]
-- as opposed to
x <- mkFreshIntVar "x"
y <- mkFreshIntVar "y"
xPlusy <- mkAdd [x,y]
Definitely! It would be very nice if we could automatically lift Haskell
Since it is all
Same as point 1. So I think there are two key ideas here worth discussing/pursuing:
Apart from these I think the current API has its place and should stay as a minimal transparent C wrapper. |
Thanks for your detailed reply! I agree that the low-level API should be kept, and the 'simpler' interface should be a separate module (or even a package).
I'm not sure how to do this, but this example looks really neat! If it's achievable, I believe most of my complaints are instantly gone.
It seems that the previous My plan is to first experiment with the previous Z3.Lang and see how it can be extended in the next few days.
I think it can be used to generate |
Sounds good, feel free to ping me or report any problems/requests here. I will think about potential designs as well and hopefully then we can draft something. |
I think it's interesting to have a deep DSL. Generate an intermediate AST, perform some checks on it, then pass it down to the lower-level Z3 library. That should help making a better higher-level API, although errors would still be caught at runtime. I personally don't have time to get into that kind of project, but I am happy to participate in discussions and review code. But I don't find a shallow DSL powered by Haskell's type hackery to be very interesting, and it's a lot harder and more work than one initially thinks. That is why we abandoned |
Hey guys! What's the current state of this issue? |
Hi! I wasn't aware of SBV when I opened this issue. I was frustrated then, because I thought Haskell deserved something better than a low level wrapper. It took me some time to discover (maybe rediscover?) SBV. SBV seems pretty complete and capable, and fulfills my current needs. I certainly see the necessity of a low-level Z3 library (the current |
The current interface IMHO is pretty primitive. The readme includes a 4queen example, but that is unnecessarily tedious, frustrating, and straight terrifying.
I believe you have more experience with z3 than me, but I made some simplifications to the 4queen example. It's still very tedious.
Specifically,
mk
.Z3
monad, so even if it's just building an AST, there must be<$>
and<*>
.sequence
s are spilled everywhere without clear motivation.mk
'd. This is an unnecessary burden.Int
inevalInt m
? The type seems to be deducible from the context.mkLe
mkSub
... They all seem unintuitive and ugly.As I personally want to use Haskell for my next z3-related project, I'm concerned with the productivity implication. I used to use z3py. Simple tasks are really simple, intuitive, and even good-looking. But complex tasks are ugly (e.g. folding over a list of expressions). Haskell-z3 seems to be on the opposite extreme, where complex tasks are made fairly easy (e.g.
assert =<< mkAnd =<< T.sequence [ mkLe _1 qi | qi <- q ]
) but simple tasks are less than ideal (e.g.mkInteger 0 >>= \_0 -> join $ mkIte <$> mkLe _0 x <*> pure x <*> mkUnaryMinus x
versus z3py's straightforwardIf(0 <= x, x, -x)
).I believe Haskell-z3 can have the best of the both worlds. But before I set out to start coding, I decide to create an issue first to gather opinions: Is a better interface really needed? What could the design be? What are the previous attempts (if any) and how they turned out to be? After a design is sketched out, I'm willing to implement it. If it's not really important or it's a dead-end, I'll save some time. :)
(IMHO, the whole situation is like embedding the Z3 language into Haskell, and we automatically get several existing designs: Free monads, GADTs, and tagless final. But I'd like to add that Template Haskell should also be considered, as it allows us to write something like
[z3| if 0 <= x then x else -x |]
instead ofmkInteger 0 >>= \_0 -> join $ mkIte <$> mkLe _0 x <*> pure x <*> mkUnaryMinus x
. This however still needs duplicating AST definitions, which is very undesirable.)The text was updated successfully, but these errors were encountered: