packages feed

quipper-demos-0.9.0.0: Quipper/Demos/TemplateTest.hs

-- | This file illustrates the most basic use of Template Haskell.

import Quipper

-- | A classical implementation of some boolean function.
build_circuit
example1 :: Bool -> Bool -> Bool
example1 a b = (a && b) || not a

-- $ The keyword \"build_circuit\" causes an equivalent quantum function
-- to be built automatically. It will have the following name and
-- type:
-- 
-- > template_example1 :: Circ (Qubit -> Circ (Qubit -> Circ Qubit))
-- 
-- The various nested 'Circ' applications are an artifact, and can and
-- should be removed using the 'unpack' operator:
-- 
-- > (unpack template_example1) :: Qubit -> Qubit -> Circ Qubit

-- | This main function prints the circuit generated from 'example1'.
main1 :: IO ()
main1 =
  print_simple Preview (unpack template_example1)

-- | Here is some other boolean function. We do not use the
-- \"build_circuit\" keyword.
fake :: Bool -> Bool
fake b = not b

-- $ Suppose we want to use the function 'fake' as a subroutine
-- elsewhere:
{-
build_circuit
example2 :: Bool -> Bool -> Bool
example2 a b = fake (a && b) || not a
-}

-- | This will fail, because build_circuit does not know how to
-- translate the 'fake' function. 
-- 
-- We can fix this by manually providing a template. This is useful in
-- two situations:
-- 
-- 1. To provide a template for a Haskell built-in function;
-- 
-- 2. To provide a more efficient template for some function than the
-- one build_circuit can build automatically.
template_fake :: Circ (Qubit -> Circ Qubit)
template_fake = return f where
  f q = do
    qnot_at q
    return q

-- | Now that a template for 'fake' has been defined, the definition
-- of 'example2' works:
build_circuit
example2 :: Bool -> Bool -> Bool
example2 a b = fake (a && b) || not a


-- | This main function prints the circuit generated from 'example2'. 
main2 :: IO ()
main2 =
  print_simple Preview (unpack template_example2)

main = main2