diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,10 @@
 # Revision history for dataframe
 
+## 0.4.0.7
+* Pretty printer for expression
+* Fix issue with how `pow` was getting displayed.
+* `exposeColumns` has been renamed to `declareColumns`
+
 ## 0.4.0.6
 * Even faster groupby: uses radix sort rather than mergesort.
 * Created `rowValue` function - `df |> D.toRowList |> map (D.rowValue some_column)`.
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -77,7 +77,7 @@
 3          | 40   
 3          | 30   
 
-dataframe> :exposeColumns df
+dataframe> :declareColumns df
 "product_id :: Expr Int"
 "sales :: Expr Int"
 dataframe> df |> D.groupBy [F.name product_id] |> D.aggregate [F.sum sales `as` "total_sales"]
diff --git a/dataframe.cabal b/dataframe.cabal
--- a/dataframe.cabal
+++ b/dataframe.cabal
@@ -1,6 +1,6 @@
 cabal-version:      2.4
 name:               dataframe
-version:            0.4.0.6
+version:            0.4.0.7
 
 synopsis: A fast, safe, and intuitive DataFrame library.
 
@@ -114,7 +114,7 @@
                       vector-algorithms ^>= 0.9,
                       zlib >= 0.5 && < 1,
                       zstd >= 0.1.2.0 && < 0.2,
-                      mmap >= 0.5.8 && <= 0.5.9,
+                      mmap >= 0.5.8 && < 0.6,
                       parallel >= 3.2.2.0 && < 5
     hs-source-dirs:   src
     c-sources:        cbits/process_csv.c
diff --git a/src/DataFrame.hs b/src/DataFrame.hs
--- a/src/DataFrame.hs
+++ b/src/DataFrame.hs
@@ -161,16 +161,16 @@
 F.max   \@t (F.col \@t "x")
 @
 
-== REPL power-tool: ':exposeColumns'
+== REPL power-tool: ':declareColumns'
 
-Use @:exposeColumns <df>@ in GHCi/IHaskell to turn each column of a bound 'DataFrame'
+Use @:declareColumns <df>@ in GHCi/IHaskell to turn each column of a bound 'DataFrame'
 into a local binding with the same (mangled if needed) name and the column's concrete
 vector type. This is great for quick ad-hoc analysis, plotting, or hand-rolled checks.
 
 @
 -- Suppose df has columns: "passengers" :: Int, "fare" :: Double, "payment" :: Text
 ghci> :set -XTemplateHaskell
-ghci> :exposeColumns df
+ghci> :declareColumns df
 
 -- Now you have in scope:
 ghci> :type passengers
@@ -276,7 +276,7 @@
     null,
     toMarkdownTable,
  )
-import DataFrame.Internal.Expression as Expression (Expr)
+import DataFrame.Internal.Expression as Expression (Expr, prettyPrint)
 import DataFrame.Internal.Row as Row (
     Any,
     Row,
diff --git a/src/DataFrame/Functions.hs b/src/DataFrame/Functions.hs
--- a/src/DataFrame/Functions.hs
+++ b/src/DataFrame/Functions.hs
@@ -216,7 +216,7 @@
 pow _ 0 = Lit 1
 pow (Lit n) i = Lit (n ^ i)
 pow expr 1 = expr
-pow expr i = UnaryOp ("pow " <> T.pack (show i)) (^ i) expr
+pow expr i = BinaryOp "pow" (^) expr (lit i)
 
 relu :: (Columnable a, Num a) => Expr a -> Expr a
 relu = UnaryOp "relu" (Prelude.max 0)
diff --git a/src/DataFrame/Internal/Expression.hs b/src/DataFrame/Internal/Expression.hs
--- a/src/DataFrame/Internal/Expression.hs
+++ b/src/DataFrame/Internal/Expression.hs
@@ -69,7 +69,7 @@
     (*) e (Lit 1) = e
     (*) (Lit x) (Lit y) = Lit (x * y)
     (*) e1 e2
-        | e1 == e2 = UnaryOp "pow 2" (^ 2) e1
+        | e1 == e2 = BinaryOp "pow" (^) e1 (Lit @Int 2)
         | otherwise = BinaryOp "mult" (*) e1 e2
 
     fromInteger :: Integer -> Expr a
@@ -311,3 +311,38 @@
 getColumns (AggVector expr op f) = getColumns expr
 getColumns (AggReduce expr op f) = getColumns expr
 getColumns (AggFold expr op acc f) = getColumns expr
+
+prettyPrint :: Expr a -> String
+prettyPrint = go 0
+  where
+    go :: Int -> Expr a -> String
+    go prec expr = case expr of
+        Col name -> T.unpack name
+        Lit value -> show value
+        If cond t e ->
+            "if " ++ go 0 cond ++ " then " ++ go 0 t ++ " else " ++ go 0 e
+        UnaryOp name _ arg -> T.unpack name ++ "(" ++ go 0 arg ++ ")"
+        BinaryOp name _ l r ->
+            let p = opPrec name
+                inner = go p l ++ " " ++ opSym name ++ " " ++ go p r
+             in if prec > p then "(" ++ inner ++ ")" else inner
+        AggVector arg op _ -> T.unpack op ++ "(" ++ go 0 arg ++ ")"
+        AggReduce arg op _ -> T.unpack op ++ "(" ++ go 0 arg ++ ")"
+        AggNumericVector arg op _ -> T.unpack op ++ "(" ++ go 0 arg ++ ")"
+        AggFold arg op _ _ -> T.unpack op ++ "(" ++ go 0 arg ++ ")"
+
+    opPrec :: T.Text -> Int
+    opPrec "add" = 1
+    opPrec "sub" = 1
+    opPrec "mult" = 2
+    opPrec "divide" = 2
+    opPrec "pow" = 3
+    opPrec _ = 0
+
+    opSym :: T.Text -> String
+    opSym "add" = "+"
+    opSym "sub" = "-"
+    opSym "mult" = "*"
+    opSym "divide" = "/"
+    opSym "pow" = "^"
+    opSym other = T.unpack other
