The ersatz package

[ Tags: algorithms, bsd3, library, logic ] [ Propose Tags ]

A monad for expressing SAT or QSAT problems using observable sharing.

For example, we can express a full-adder with:

full_adder :: Bit -> Bit -> Bit -> (Bit, Bit)
full_adder a b cin = (s2, c1 || c2)
  where (s1,c1) = half_adder a b
        (s2,c2) = half_adder s1 cin
half_adder :: Bit -> Bit -> (Bit, Bit)
half_adder a b = (a `xor` b, a && b)

[Skip to Readme]


Versions 0.1,,, 0.2,, 0.2.4, 0.2.5,, 0.2.6,, 0.3, 0.3.1, 0.4, 0.4.1, 0.4.2
Change log
Dependencies array (>=0.2 && <0.5), base (>=4.5 && <6), containers (>=, data-default (==0.5.*), ghc-prim, mtl (>=1.1 && <2.2), process (==1.1.*), temporary (==1.1.*), transformers (==0.3.*), unordered-containers (==0.2.*) [details]
License BSD3
Copyright (c) 2010-2013 Edward Kmett, (c) 2013 Johan Kiviniemi
Author Edward A. Kmett, Johan Kiviniemi
Maintainer Edward A. Kmett <>
Category Logic, Algorithms
Home page
Bug tracker
Source repo head: git clone git://
Uploaded Sat Mar 9 09:17:26 UTC 2013 by EdwardKmett
Updated Sat Jul 11 22:45:43 UTC 2015 by EdwardKmett to revision 1   [What is this?]
Distributions LTSHaskell:0.4.2, NixOS:0.4.2, Stackage:0.4.2, openSUSE:0.4.2
Downloads 5752 total (151 in the last 30 days)
Rating 2.0 (votes: 1) [estimated by rule of succession]
Your Rating
  • λ
  • λ
  • λ
Status Docs uploaded by user
Build status unknown [no reports yet]
Hackage Matrix CI




Note: This package has metadata revisions in the cabal description newer than included in the tarball. To unpack the package including the revisions, use 'cabal get'.

Maintainer's Corner

For package maintainers and hackage trustees

Readme for ersatz-

[back to package description]


Build Status

Ersatz is a library for generating QSAT (CNF/QBF) problems using a monad. It takes care of generating the normal form, encoding your problem, marshaling the data to an external solver, and parsing and interpreting the result into Haskell types.

What differentiates Ersatz is the use of observable sharing in the API.

For instance to define a full adder:

full_adder :: Bit -> Bit -> Bit -> (Bit, Bit)
full_adder a b cin = (s2, c1 || c2)
  where (s1,c1) = half_adder a b
        (s2,c2) = half_adder s1 cin

half_adder :: Bit -> Bit -> (Bit, Bit)
half_adder a b = (a `xor` b, a && b)

as opposed to the following code in satchmo:

full_adder :: Boolean -> Boolean -> Boolean
           -> SAT ( Boolean, Boolean )
full_adder a b c = do
  let s x y z = sum $ map fromEnum [x,y,z]
  r <- fun3 ( \ x y z -> odd $ s x y z ) a b c
  d <- fun3 ( \ x y z -> 1   < s x y z ) a b c
  return ( r, d )

half_adder :: Boolean -> Boolean
           -> SAT ( Boolean, Boolean )
half_adder a b = do
  let s x y = sum $ map fromEnum [x,y]
  r <- fun2 ( \ x y -> odd $ s x y ) a b
  d <- fun2 ( \ x y -> 1   < s x y ) a b
  return ( r, d )

This enables you to use the a much richer subset of Haskell than the purely monadic meta-language, and it becomes much easier to see that the resulting encoding is correct.

To allocate fresh existentially or universally quantified variables or to assert that a Bit is true and add the attendant circuit with sharing to the current problem you use the SAT monad.

verify_currying :: SAT m ()
verify_currying = do
  (x::Bit, y::Bit, z::Bit) <- forall
  assert $ ((x && y) ==> z) === (x ==> y ==> z)

We can then hand that off to a SAT solver, and get back an answer:

main = solveWith minisat verify_currying >>= print

Support is offered for decoding various Haskell datatypes from the solution provided by the SAT solver.

Contact Information

Contributions and bug reports are welcome!

Please feel free to contact me through github or on the #haskell IRC channel on

-Edward Kmett