diff --git a/Data/Array/Accelerate.hs b/Data/Array/Accelerate.hs
--- a/Data/Array/Accelerate.hs
+++ b/Data/Array/Accelerate.hs
@@ -35,10 +35,10 @@
   Elem,
 
   -- * Array shapes & indices
-  Ix(..), All(..), SliceIx(..), DIM0, DIM1, DIM2, DIM3, DIM4, DIM5,
+  Ix(dim, size), All(..), SliceIx(..), DIM0, DIM1, DIM2, DIM3, DIM4, DIM5,
   
   -- * Array operations
-  shape, indexArray, fromIArray, toIArray, fromList, toList, Arrays,
+  arrayShape, indexArray, fromIArray, toIArray, fromList, toList, Arrays,
 
   -- * Surface language
   module Data.Array.Accelerate.Language,
@@ -47,10 +47,14 @@
 
 -- friends
 import Data.Array.Accelerate.Type
-import Data.Array.Accelerate.Array.Sugar hiding ((!))
+import Data.Array.Accelerate.Array.Sugar hiding ((!), shape)
 import qualified Data.Array.Accelerate.Array.Sugar as Sugar
 import Data.Array.Accelerate.Language
 
--- rename as (!) is already used by the EDSL for indexing
+-- rename as '(!)' is already used by the EDSL for indexing
 indexArray :: Array dim e -> dim -> e
 indexArray = (Sugar.!)
+
+-- rename as 'shape' is already used by the EDSL to query an array's shape
+arrayShape :: Ix dim => Array dim e -> dim
+arrayShape = Sugar.shape
diff --git a/Data/Array/Accelerate/AST.hs b/Data/Array/Accelerate/AST.hs
--- a/Data/Array/Accelerate/AST.hs
+++ b/Data/Array/Accelerate/AST.hs
@@ -116,11 +116,19 @@
   
   -- Local binding to represent sharing and demand explicitly; this is an
   -- eager(!) binding
-  Let         :: OpenAcc aenv (Array dim e)         -- ^bound expressions 
-              -> OpenAcc (aenv, Array dim e) (Array dim' e')           
-                                                    -- ^the bound expr's scope
+  Let         :: OpenAcc aenv (Array dim e)         -- bound expression
+              -> OpenAcc (aenv, Array dim e) 
+                         (Array dim' e')            -- the bound expr's scope           
               -> OpenAcc aenv (Array dim' e')
 
+  -- Variant of 'Let' binding (and decomposing) a pair
+  Let2        :: OpenAcc aenv (Array dim1 e1, 
+                               Array dim2 e2)       -- bound expressions 
+              -> OpenAcc ((aenv, Array dim1 e1), 
+                                 Array dim2 e2)
+                         (Array dim' e')            -- the bound expr's scope           
+              -> OpenAcc aenv (Array dim' e')
+
   -- Variable bound by a 'Let', represented by a de Bruijn index              
   Avar        :: Idx     aenv (Array dim e)
               -> OpenAcc aenv (Array dim e)
@@ -135,26 +143,26 @@
               -> OpenAcc aenv (Scalar e)
 
   -- Change the shape of an array without altering its contents
-  -- * precondition: size dim == size dim'
+  -- > precondition: size dim == size dim'
   Reshape     :: Ix dim
-              => Exp     aenv dim                 -- ^new shape
-              -> OpenAcc aenv (Array dim' e)      -- ^array to be reshaped
+              => Exp     aenv dim                 -- new shape
+              -> OpenAcc aenv (Array dim' e)      -- array to be reshaped
               -> OpenAcc aenv (Array dim e)
 
   -- Replicate an array across one or more dimensions as given by the first
   -- argument
   Replicate   :: Ix dim
-              => SliceIndex slix sl co dim        -- ^slice type specification
-              -> Exp     aenv slix                -- ^slice value specification
-              -> OpenAcc aenv (Array sl e)        -- ^data to be replicated
+              => SliceIndex slix sl co dim        -- slice type specification
+              -> Exp     aenv slix                -- slice value specification
+              -> OpenAcc aenv (Array sl e)        -- data to be replicated
               -> OpenAcc aenv (Array dim e)
 
   -- Index a subarray out of an array; i.e., the dimensions not indexed are 
   -- returned whole
   Index       :: Ix sl
-              => SliceIndex slix sl co dim        -- ^slice type specification
-              -> OpenAcc aenv (Array dim e)       -- ^array to be indexed
-              -> Exp     aenv slix                -- ^slice value specification
+              => SliceIndex slix sl co dim        -- slice type specification
+              -> OpenAcc aenv (Array dim e)       -- array to be indexed
+              -> Exp     aenv slix                -- slice value specification
               -> OpenAcc aenv (Array sl e)
 
   -- Apply the given unary function to all elements of the given array
@@ -173,17 +181,11 @@
               -> OpenAcc aenv (Array dim e2)
               -> OpenAcc aenv (Array dim e3)
 
-  -- Remove all elements from a linear array that do not satisfy the given
-  -- predicate
-  Filter      :: Fun     aenv (e -> ElemRepr Bool) 
-              -> OpenAcc aenv (Vector e)
-              -> OpenAcc aenv (Vector e)
-
   -- Fold of an array with a given *associative* function and its neutral
   -- element
-  Fold        :: Fun     aenv (e -> e -> e)          -- ^combination function
-              -> Exp     aenv e                      -- ^default value
-              -> OpenAcc aenv (Array dim e)          -- ^folded array
+  Fold        :: Fun     aenv (e -> e -> e)          -- combination function
+              -> Exp     aenv e                      -- default value
+              -> OpenAcc aenv (Array dim e)          -- folded array
               -> OpenAcc aenv (Scalar e)
     -- FIXME: generalise to Gabi's mapFold
 
@@ -191,9 +193,9 @@
   -- function and its neutral element; produces a rightmost fold value and a
   -- linear of the same shape (the fold value would be the rightmost element
   -- in a scan, as opposed to a prescan)
-  Scan        :: Fun     aenv (e -> e -> e)          -- ^combination function
-              -> Exp     aenv e                      -- ^default value
-              -> OpenAcc aenv (Vector e)             -- ^linear array
+  Scan        :: Fun     aenv (e -> e -> e)          -- combination function
+              -> Exp     aenv e                      -- default value
+              -> OpenAcc aenv (Vector e)             -- linear array
               -> OpenAcc aenv (Vector e, Scalar e)
     -- FIXME: generalised multi-dimensional scan?  And/or a generalised mapScan?
 
@@ -206,20 +208,21 @@
   -- some positions in the target array are never picked by the permutation
   -- functions).  Moroever, we have a combination function (in case some
   -- positions on the target array are picked multiple times by the
-  -- permutation functions).  The combination functions needs to be
-  -- *associative* and *commutative*.  
-  Permute     :: Fun     aenv (e -> e -> e)        -- ^combination function
-              -> OpenAcc aenv (Array dim' e)       -- ^default values
-              -> Fun     aenv (dim -> dim')        -- ^permutation function
-              -> OpenAcc aenv (Array dim e)        -- ^source array
+  -- permutation functions).  The combination function needs to be
+  -- /associative/ and /commutative/ .  We drop every element for which the
+  -- permutation function yields -1 (i.e., a tuple of -1 values).
+  Permute     :: Fun     aenv (e -> e -> e)        -- combination function
+              -> OpenAcc aenv (Array dim' e)       -- default values
+              -> Fun     aenv (dim -> dim')        -- permutation function
+              -> OpenAcc aenv (Array dim e)        -- source array
               -> OpenAcc aenv (Array dim' e)
 
   -- Generalised multi-dimensional backwards permutation; the permutation can
   -- be between arrays of varying shape; the permutation function must be total
   Backpermute :: Ix dim'
-              => Exp     aenv dim'                 -- ^dimensions of the result
-              -> Fun     aenv (dim' -> dim)        -- ^permutation function
-              -> OpenAcc aenv (Array dim e)        -- ^source array
+              => Exp     aenv dim'                 -- dimensions of the result
+              -> Fun     aenv (dim' -> dim)        -- permutation function
+              -> OpenAcc aenv (Array dim e)        -- source array
               -> OpenAcc aenv (Array dim' e)
 
 -- |Closed array expression aka an array program
@@ -246,17 +249,17 @@
 --
 data OpenExp env aenv t where
 
-  -- |Variable index, ranging only over tuples or scalars
+  -- Variable index, ranging only over tuples or scalars
   Var         :: ArrayElem t
               => Idx env t 
               -> OpenExp env aenv t
 
-  -- |Constant values
+  -- Constant values
   Const       :: Elem t
               => t                              -- not converted to ElemRepr yet
               -> OpenExp env aenv (ElemRepr t)
 
-  -- |Tuples
+  -- Tuples
   Pair        :: (Elem s, Elem t)
               => s {- dummy to fix the type variable -}
               -> t {- dummy to fix the type variable -}
@@ -274,30 +277,30 @@
               -> OpenExp env aenv (ElemRepr (s, t))
               -> OpenExp env aenv (ElemRepr t)
 
-  -- |Conditional expression (non-strict in 2nd and 3rd argument)
+  -- Conditional expression (non-strict in 2nd and 3rd argument)
   Cond        :: OpenExp env aenv (ElemRepr Bool) 
               -> OpenExp env aenv t 
               -> OpenExp env aenv t 
               -> OpenExp env aenv t
 
-  -- |Primitive constants
+  -- Primitive constants
   PrimConst   :: Elem t
               => PrimConst t -> OpenExp env aenv (ElemRepr t)
 
-  -- |Primitive scalar operations
+  -- Primitive scalar operations
   PrimApp     :: (Elem a, Elem r)
               => PrimFun (a -> r) 
               -> OpenExp env aenv (ElemRepr a) 
               -> OpenExp env aenv (ElemRepr r)
 
-  -- |Project a single scalar from an array
-  -- * the array expression cannot contain any free scalar variables
+  -- Project a single scalar from an array
+  -- the array expression cannot contain any free scalar variables
   IndexScalar :: OpenAcc aenv (Array dim t) 
               -> OpenExp env aenv dim 
               -> OpenExp env aenv t
 
-  -- |Array shape
-  -- * the array expression cannot contain any free scalar variables
+  -- Array shape
+  -- the array expression cannot contain any free scalar variables
   Shape       :: OpenAcc aenv (Array dim e) 
               -> OpenExp env aenv dim
             
@@ -372,6 +375,9 @@
   --        ALSO: need to use overloading
 
   -- FIXME: conversions between various integer types
+  --        should we have an overloaded functions like 'toInt'?  
+  --        (or 'fromEnum' for enums?)
+  PrimBoolToInt     :: PrimFun (Bool -> Int)
 
   -- FIXME: what do we want to do about Enum?  succ and pred are only
   --   moderatly useful without user-defined enumerations, but we want
diff --git a/Data/Array/Accelerate/Array/Representation.hs b/Data/Array/Accelerate/Array/Representation.hs
--- a/Data/Array/Accelerate/Array/Representation.hs
+++ b/Data/Array/Accelerate/Array/Representation.hs
@@ -47,8 +47,8 @@
 --
 data Array dim e where
   Array :: (Ix dim, ArrayElem e) 
-        => dim             -- ^extent of dimensions = shape
-        -> ArrayData e     -- ^data
+        => dim             -- extent of dimensions = shape
+        -> ArrayData e     -- data
         -> Array dim e
 
 -- |Shorthand for common shape representations
@@ -71,17 +71,18 @@
 
 -- |Class of index representations (which are nested pairs)
 --
-class Ix ix where
-  dim       :: ix -> Int       -- ^number of dimensions (>= 0)
-  size      :: ix -> Int       -- ^for a *shape* yield the total number of 
+class Eq ix => Ix ix where
+  dim       :: ix -> Int       -- number of dimensions (>= 0)
+  size      :: ix -> Int       -- for a *shape* yield the total number of 
                                -- elements in that array
-  intersect :: ix -> ix -> ix  -- ^yield the intersection of two shapes
-  index     :: ix -> ix -> Int -- ^yield the index position in a linear, 
+  intersect :: ix -> ix -> ix  -- yield the intersection of two shapes
+  ignore    :: ix              -- identifies ignored elements in 'permute'
+  index     :: ix -> ix -> Int -- yield the index position in a linear, 
                                -- row-major representation of the array
                                -- (first argument is the shape)
 
   iter  :: ix -> (ix -> a) -> (a -> a -> a) -> a -> a
-                               -- ^iterate through the entire shape, applying
+                               -- iterate through the entire shape, applying
                                -- the function; third argument combines results
                                -- and fourth is returned in case of an empty
                                -- iteration space; the index space is traversed
@@ -96,6 +97,7 @@
   dim       ()       = 0
   size      ()       = 1
   intersect () ()    = ()
+  ignore             = ()
   index     () ()    = 0
   iter      () f _ _ = f ()
   
@@ -106,6 +108,7 @@
   dim (sh, _)                       = dim sh + 1
   size (sh, sz)                     = size sh * sz
   (sh1, sz1) `intersect` (sh2, sz2) = (sh1 `intersect` sh2, sz1 `min` sz2)
+  ignore                            = (ignore, -1)
   index (sh, sz) (ix, i) 
     | i >= 0 && i < sz              = index sh ix + size sh * i
     | otherwise              
diff --git a/Data/Array/Accelerate/Array/Sugar.hs b/Data/Array/Accelerate/Array/Sugar.hs
--- a/Data/Array/Accelerate/Array/Sugar.hs
+++ b/Data/Array/Accelerate/Array/Sugar.hs
@@ -496,8 +496,8 @@
 --
 data Array dim e where
   Array :: (Ix dim, Elem e) 
-        => dim                        -- ^extent of dimensions = shape
-        -> ArrayData (ElemRepr e)     -- ^data, same layout as in
+        => dim                        -- extent of dimensions = shape
+        -> ArrayData (ElemRepr e)     -- data, same layout as in
         -> Array dim e
 
 -- |Scalars
@@ -557,12 +557,13 @@
 -- |Indices as n-tuples
 --
 class (Shape ix, Repr.Ix (ElemRepr ix)) => Ix ix where
-  dim   :: ix -> Int           -- ^number of dimensions (>= 0)
-  size  :: ix -> Int           -- ^for a *shape* yield the total number of 
-                               -- elements in that array
-  index :: ix -> ix -> Int     -- ^corresponding index into a linear, row-major 
-                               -- representation of the array (first argument
-                               -- is the shape)
+  dim    :: ix -> Int           -- number of dimensions (>= 0)
+  size   :: ix -> Int           -- for a *shape* yield the total number of 
+                                -- elements in that array
+  ignore :: ix                  -- identifies ignored elements in 'permute'
+  index  :: ix -> ix -> Int     -- corresponding index into a linear, row-major 
+                                -- representation of the array (first argument
+                                -- is the shape)
 
   rangeToShape ::  (ix, ix) -> ix   -- convert a minpoint-maxpoint index
                                     -- into a shape
@@ -570,6 +571,7 @@
 
   dim         = Repr.dim . fromElem
   size        = Repr.size . fromElem
+  ignore      = toElem Repr.ignore
   index sh ix = Repr.index (fromElem sh) (fromElem ix)
   
   rangeToShape (low, high) 
diff --git a/Data/Array/Accelerate/Interpreter.hs b/Data/Array/Accelerate/Interpreter.hs
--- a/Data/Array/Accelerate/Interpreter.hs
+++ b/Data/Array/Accelerate/Interpreter.hs
@@ -21,6 +21,7 @@
 ) where
 
 -- standard libraries
+import Control.Monad
 import Data.Bits
 import Data.Char                (chr, ord)
 
@@ -72,6 +73,10 @@
   = let !arr1 = force $ evalOpenAcc acc1 aenv
     in evalOpenAcc acc2 (aenv `Push` arr1)
 
+evalOpenAcc (Let2 acc1 acc2) aenv 
+  = let (!arr1, !arr2) = force $ evalOpenAcc acc1 aenv
+    in evalOpenAcc acc2 (aenv `Push` arr1 `Push` arr2)
+
 evalOpenAcc (Avar idx) aenv = delay $ prj idx aenv
 
 evalOpenAcc (Use arr) _aenv = delay arr
@@ -92,9 +97,6 @@
 evalOpenAcc (ZipWith f acc1 acc2) aenv
   = zipWithOp (evalFun f aenv) (evalOpenAcc acc1 aenv) (evalOpenAcc acc2 aenv)
 
-evalOpenAcc (Filter p acc) aenv
-  = filterOp (evalFun p aenv) (evalOpenAcc acc aenv)
-  
 evalOpenAcc (Fold f e acc) aenv
   = foldOp (evalFun f aenv) (evalExp e aenv) (evalOpenAcc acc aenv)
 
@@ -193,12 +195,6 @@
 zipWithOp f (DelayedArray sh1 rf1) (DelayedArray sh2 rf2) 
   = DelayedArray (sh1 `intersect` sh2) (\ix -> f (rf1 ix) (rf2 ix))
 
-filterOp :: (e -> Sugar.ElemRepr Bool)
-         -> Delayed (Vector e)
-         -> Delayed (Vector e)
-filterOp p (DelayedArray sh rf)
-  = error "Data.Array.Accelerate.Interpreter: filter: not yet implemented"
-
 foldOp :: (e -> e -> e)
        -> e
        -> Delayed (Array dim e)
@@ -247,9 +243,11 @@
             -- the target dimension (where it gets combined with the current
             -- default)
           let update ix = do
-                            let i = index dftsSh (p ix)
-                            e <- readArrayData arr i
-                            writeArrayData arr i (pf ix `f` e) 
+                            let target = p ix
+                            unless (target == ignore) $ do
+                              let i = index dftsSh target
+                              e <- readArrayData arr i
+                              writeArrayData arr i (pf ix `f` e) 
           iter sh update (>>) (return ())
           
             -- return the updated array
@@ -370,6 +368,7 @@
 evalPrim PrimRoundFloatInt = evalRoundFloatInt
 evalPrim PrimTruncFloatInt = evalTruncFloatInt
 evalPrim PrimIntFloat      = evalIntFloat
+evalPrim PrimBoolToInt     = evalBoolToInt
 
 
 -- Pairing
@@ -426,6 +425,9 @@
 
 evalIntFloat :: Int -> Float
 evalIntFloat = fromIntegral
+
+evalBoolToInt :: Bool -> Int
+evalBoolToInt = fromEnum
 
 
 -- Extract methods from reified dictionaries
diff --git a/Data/Array/Accelerate/Language.hs b/Data/Array/Accelerate/Language.hs
--- a/Data/Array/Accelerate/Language.hs
+++ b/Data/Array/Accelerate/Language.hs
@@ -30,12 +30,15 @@
   -- * Shape manipulation
   reshape,
 
-  -- * Indexing
-  (!),
-
   -- * Collective array operations
-  replicate, zip, map, zipWith, filter, scan, fold, permute, backpermute,
+  slice, replicate, zip, map, zipWith, scan, fold, permute, backpermute,
   
+  -- * Conditional expressions
+  (?),
+  
+  -- * Array operations with a scalar result
+  (!), shape,
+  
   -- * Instances of Bounded, Enum, Eq, Ord, Bits, Num, Real, Floating,
   --   Fractional, RealFrac, RealFloat
 
@@ -44,7 +47,13 @@
   (==*), (/=*), (<*), (<=*), (>*), (>=*), max, min,
 
   -- * Standard functions that we need to redefine as their signatures change
-  (&&*), (||*), not
+  (&&*), (||*), not,
+  
+  -- * Conversions
+  boolToInt,
+  
+  -- * Constants
+  ignore
 
 ) where
 
@@ -58,18 +67,13 @@
 
 -- friends
 import Data.Array.Accelerate.Type
-import Data.Array.Accelerate.Array.Sugar hiding ((!))
+import Data.Array.Accelerate.Array.Sugar hiding ((!), ignore, shape)
+import qualified Data.Array.Accelerate.Array.Sugar as Sugar
 import Data.Array.Accelerate.Smart
 
 
-infixr 2 ||*
-infixr 3 &&*
-infix  4 ==*, /=*, <*, <=*, >*, >=*
-infixl 9 !
-
-
--- |Collective operations
--- ----------------------
+-- Collective operations
+-- ---------------------
 
 use :: (Ix dim, Elem e) => Array dim e -> Acc (Array dim e)
 use = Use
@@ -89,11 +93,11 @@
           -> Acc (Array (SliceDim slix) e)
 replicate = Replicate (undefined::slix) (undefined::e)
 
-(!) :: forall slix e. (SliceIx slix, Elem e) 
-    => Acc (Array (SliceDim slix) e) 
-    -> Exp slix 
-    -> Acc (Array (Slice slix) e)
-(!) = Index (undefined::slix) (undefined::e) 
+slice :: forall slix e. (SliceIx slix, Elem e) 
+      => Acc (Array (SliceDim slix) e) 
+      -> Exp slix 
+      -> Acc (Array (Slice slix) e)
+slice = Index (undefined::slix) (undefined::e) 
 
 zip :: (Ix dim, Elem a, Elem b) 
     => Acc (Array dim a)
@@ -114,18 +118,12 @@
         -> Acc (Array dim c)
 zipWith = ZipWith
 
-filter :: Elem a 
-       => (Exp a -> Exp Bool) 
-       -> Acc (Vector a) 
-       -> Acc (Vector a)
-filter = Filter
-
 scan :: Elem a 
      => (Exp a -> Exp a -> Exp a) 
      -> Exp a 
      -> Acc (Vector a)
-     -> Acc (Vector a, Scalar a)
-scan = Scan
+     -> (Acc (Vector a), Acc (Scalar a))
+scan f e arr = unpair (Scan f e arr)
 
 fold :: Elem a 
      => (Exp a -> Exp a -> Exp a) 
@@ -150,9 +148,28 @@
 backpermute = Backpermute
 
 
--- |Instances of all relevant H98 classes
--- --------------------------------------
+-- Conditional expressions
+-- -----------------------
 
+infix 0 ?
+(?) :: Elem t => Exp Bool -> (Exp t, Exp t) -> Exp t
+c ? (t, e) = Cond c t e
+
+
+-- Array operations with a scalar result
+-- -------------------------------------
+
+infixl 9 !
+(!) :: (Ix dim, Elem e) => Acc (Array dim e) -> Exp dim -> Exp e
+(!) = IndexScalar
+
+shape :: Ix dim => Acc (Array dim e) -> Exp dim
+shape = Shape
+
+
+-- Instances of all relevant H98 classes
+-- -------------------------------------
+
 instance (Elem t, IsBounded t) => Bounded (Exp t) where
   minBound = mkMinBound
   maxBound = mkMaxBound
@@ -214,9 +231,11 @@
   -- FIXME: add ops
 
 
--- |Methods from H98 classes, where we need other signatures
--- ---------------------------------------------------------
+-- Methods from H98 classes, where we need other signatures
+-- --------------------------------------------------------
 
+infix 4 ==*, /=*, <*, <=*, >*, >=*
+
 (==*) :: (Elem t, IsScalar t) => Exp t -> Exp t -> Exp Bool
 (==*) = mkEq
 
@@ -245,15 +264,30 @@
 min = mkMin
 
 
--- |Non-overloaded standard functions, where we need other signatures
--- ------------------------------------------------------------------
+-- Non-overloaded standard functions, where we need other signatures
+-- -----------------------------------------------------------------
 
+infixr 3 &&*
 (&&*) :: Exp Bool -> Exp Bool -> Exp Bool
 (&&*) = mkLAnd
 
+infixr 2 ||*
 (||*) :: Exp Bool -> Exp Bool -> Exp Bool
 (||*) = mkLOr
 
 not :: Exp Bool -> Exp Bool
 not = mkLNot
 
+
+-- Conversions
+-- -----------
+
+boolToInt :: Exp Bool -> Exp Int
+boolToInt = mkBoolToInt
+
+
+-- Constants
+-- ---------
+
+ignore :: Ix dim => Exp dim
+ignore = constant Sugar.ignore
diff --git a/Data/Array/Accelerate/Pretty.hs b/Data/Array/Accelerate/Pretty.hs
--- a/Data/Array/Accelerate/Pretty.hs
+++ b/Data/Array/Accelerate/Pretty.hs
@@ -45,8 +45,12 @@
 --
 prettyAcc :: Int -> OpenAcc aenv a -> Doc
 prettyAcc lvl (Let acc1 acc2) 
-  = text "let a" <> int lvl <+> text " = " <+> prettyAcc lvl acc1 <+>
+  = text "let a" <> int lvl <+> char '=' <+> prettyAcc lvl acc1 <+>
     text " in " <+> prettyAcc (lvl + 1) acc2
+prettyAcc lvl (Let2 acc1 acc2) 
+  = text "let (a" <> int lvl <> text ", a" <> int (lvl + 1) <+> char '=' <+>
+    prettyAcc lvl acc1 <+>
+    text " in " <+> prettyAcc (lvl + 2) acc2
 prettyAcc _   (Avar idx)       = text $ "a" ++ show (idxToInt idx)
 prettyAcc _   (Use arr)        = prettyArrOp "use" [prettyArray arr]
 prettyAcc lvl (Unit e)         = prettyArrOp "unit" [prettyExp lvl parens e]
@@ -62,8 +66,6 @@
   = prettyArrOp "zipWith"
       [parens (prettyFun lvl f), prettyAccParens lvl acc1, 
        prettyAccParens lvl acc2]
-prettyAcc lvl (Filter p acc)   
-  = prettyArrOp "filter" [parens (prettyFun lvl p), prettyAccParens lvl acc]
 prettyAcc lvl (Fold f e acc)   
   = prettyArrOp "fold" [parens (prettyFun lvl f), prettyExp lvl parens e,
                         prettyAccParens lvl acc]
@@ -176,6 +178,7 @@
 prettyPrim PrimRoundFloatInt = text "round"
 prettyPrim PrimTruncFloatInt = text "trunc"
 prettyPrim PrimIntFloat      = text "intFloat"
+prettyPrim PrimBoolToInt     = text "boolToInt"
 
 {-
 -- Pretty print type
diff --git a/Data/Array/Accelerate/Smart.hs b/Data/Array/Accelerate/Smart.hs
--- a/Data/Array/Accelerate/Smart.hs
+++ b/Data/Array/Accelerate/Smart.hs
@@ -20,6 +20,9 @@
   
   -- * HOAS -> de Bruijn conversion
   convertAcc, convertClosedExp,
+  
+  -- * Smart constructors for unpairing
+  unpair,
 
   -- * Smart constructors for literals
   constant,
@@ -30,7 +33,7 @@
   -- * Smart constructors for primitive functions
   mkAdd, mkSub, mkMul, mkNeg, mkAbs, mkSig, mkQuot, mkRem, mkIDiv, mkMod,
   mkBAnd, mkBOr, mkBXor, mkBNot, mkFDiv, mkRecip, mkLt, mkGt, mkLtEq, mkGtEq,
-  mkEq, mkNEq, mkMax, mkMin, mkLAnd, mkLOr, mkLNot,
+  mkEq, mkNEq, mkMax, mkMin, mkLAnd, mkLOr, mkLNot, mkBoolToInt
 
 ) where
 
@@ -40,10 +43,6 @@
 
 -- friends
 import Data.Array.Accelerate.Type
-{-
-import Data.Array.Accelerate.Array.Representation hiding (
-  Array(..), Scalar, Vector)
--}
 import Data.Array.Accelerate.Array.Sugar
 import Data.Array.Accelerate.AST hiding (OpenAcc(..), Acc, OpenExp(..), Exp)
 import qualified Data.Array.Accelerate.AST                  as AST
@@ -54,6 +53,11 @@
 -- --------------------------
 
 data Acc a where
+  
+  FstArray    :: Acc (Array dim1 e1, Array dim2 e2)
+              -> Acc (Array dim1 e1)
+  SndArray    :: Acc (Array dim1 e1, Array dim2 e2)
+              -> Acc (Array dim2 e2)
 
   Use         :: Array dim e -> Acc (Array dim e)
   Unit        :: Elem e
@@ -84,10 +88,6 @@
               -> Acc (Array dim e1)
               -> Acc (Array dim e2)
               -> Acc (Array dim e3)
-  Filter      :: Elem e
-              => (Exp e -> Exp Bool) 
-              -> Acc (Vector e)
-              -> Acc (Vector e)
   Fold        :: Elem e
               => (Exp e -> Exp e -> Exp e)
               -> Exp e
@@ -119,6 +119,10 @@
 convertOpenAcc :: Layout aenv aenv 
                -> Acc a 
                -> AST.OpenAcc aenv (ArraysRepr a)
+convertOpenAcc alyt (FstArray acc)
+  = AST.Let2 (convertOpenAcc alyt acc) (AST.Avar (AST.SuccIdx AST.ZeroIdx))
+convertOpenAcc alyt (SndArray acc)
+  = AST.Let2 (convertOpenAcc alyt acc) (AST.Avar AST.ZeroIdx)
 convertOpenAcc _    (Use array)     = AST.Use (fromArray array)
 convertOpenAcc alyt (Unit e)        = AST.Unit (convertExp alyt e)
 convertOpenAcc alyt (Reshape e acc) 
@@ -134,8 +138,6 @@
   = AST.ZipWith (convertFun2 alyt f) 
                 (convertOpenAcc alyt acc1)
                 (convertOpenAcc alyt acc2)
-convertOpenAcc alyt (Filter p acc) 
-  = AST.Filter (convertFun1 alyt p) (convertOpenAcc alyt acc)
 convertOpenAcc alyt (Fold f e acc) 
   = AST.Fold (convertFun2 alyt f) (convertExp alyt e) (convertOpenAcc alyt acc)
 convertOpenAcc alyt (Scan f e acc) 
@@ -309,14 +311,22 @@
 -- |Smart constructors to construct HOAS AST expressions
 -- -----------------------------------------------------
 
--- |Smart constructor for literals
--- -
+-- Pushes the 'Acc' constructor through a pair
+--
+unpair :: (Ix dim1, Ix dim2, Elem e1, Elem e2)
+       => Acc (Array dim1 e1, Array dim2 e2) 
+       -> (Acc (Array dim1 e1), Acc (Array dim2 e2))
+unpair acc = (FstArray acc, SndArray acc)
 
+
+-- Smart constructor for literals
+-- 
+
 constant :: Elem t => t -> Exp t
 constant = Const
 
--- |Smart constructor for constants
--- -
+-- Smart constructor for constants
+-- 
 
 mkMinBound :: (Elem t, IsBounded t) => Exp t
 mkMinBound = PrimConst (PrimMinBound boundedType)
@@ -327,8 +337,8 @@
 mkPi :: (Elem r, IsFloating r) => Exp r
 mkPi = PrimConst (PrimPi floatingType)
 
--- |Smart constructors for primitive applications
--- -
+-- Smart constructors for primitive applications
+-- 
 
 -- Operators from Num
 
@@ -426,3 +436,9 @@
 -- FIXME: Character conversions
 
 -- FIXME: Numeric conversions
+
+-- FIXME: Other conversions
+
+mkBoolToInt :: Exp Bool -> Exp Int
+mkBoolToInt b = PrimBoolToInt `PrimApp` b
+
diff --git a/Data/Array/Accelerate/Type.hs b/Data/Array/Accelerate/Type.hs
--- a/Data/Array/Accelerate/Type.hs
+++ b/Data/Array/Accelerate/Type.hs
@@ -97,7 +97,7 @@
 -- |Non-numeric types supported in array computations.
 --
 data NonNumType a where
-  TypeBool    :: NonNumDict Bool      -> NonNumType Bool   -- ^marshaled to CInt
+  TypeBool    :: NonNumDict Bool      -> NonNumType Bool   --  marshaled to CInt
   TypeChar    :: NonNumDict Char      -> NonNumType Char
   TypeCChar   :: NonNumDict CChar     -> NonNumType CChar
   TypeCSChar  :: NonNumDict CSChar    -> NonNumType CSChar
diff --git a/accelerate.cabal b/accelerate.cabal
--- a/accelerate.cabal
+++ b/accelerate.cabal
@@ -1,5 +1,5 @@
 Name:			accelerate
-Version:		0.4.0
+Version:		0.5.0.0
 Cabal-version: 		>= 1.6
 Tested-with: 		GHC >= 6.10.1
 
@@ -38,6 +38,7 @@
 			Data.Array.Accelerate.Type
 Extra-source-files:  	INSTALL
 			examples/simple/DotP.hs
+			examples/simple/Filter.hs
 			examples/simple/Main.hs
 			examples/simple/Makefile
 			examples/simple/SAXPY.hs
diff --git a/examples/simple/Filter.hs b/examples/simple/Filter.hs
new file mode 100644
--- /dev/null
+++ b/examples/simple/Filter.hs
@@ -0,0 +1,37 @@
+{-# LANGUAGE FlexibleContexts #-}
+
+module Filter (filter, filter_ref) where
+
+import Prelude   hiding (replicate, zip, map, filter, max, min, not, zipWith)
+import qualified Prelude
+
+import Data.Array.Unboxed (UArray)
+import Data.Array.IArray  (IArray)
+import qualified Data.Array.IArray as IArray
+
+import Data.Array.Accelerate
+
+filter :: Elem a 
+       => (Exp a -> Exp Bool) 
+       -> Acc (Vector a)
+       -> Acc (Vector a)
+filter p arr
+  = let flags               = map (boolToInt . p) arr
+        (targetIdx, length) = scan (+) 0 flags
+        arr'                = backpermute (length!(constant ())) id arr
+    in
+    permute const arr' (\ix -> flags!ix ==* 0 ? (ignore, targetIdx!ix)) arr
+    -- FIXME: This is abusing 'permute' in that the first two arguments are
+    --        only justified because we know the permutation function will
+    --        write to each location in the target exactly once.
+    --        Instead, we should have a primitive that directly encodes the
+    --        compaction pattern of the permutation function.
+
+filter_ref :: IArray UArray e 
+           => (e -> Bool)
+           -> UArray Int e 
+           -> UArray Int e
+filter_ref p xs
+  = let xs' = Prelude.filter p (IArray.elems xs)
+    in
+    IArray.listArray (0, length xs' - 1) xs'
diff --git a/examples/simple/Main.hs b/examples/simple/Main.hs
--- a/examples/simple/Main.hs
+++ b/examples/simple/Main.hs
@@ -2,6 +2,8 @@
 
 module Main where
 
+import Prelude hiding (filter)
+
 import Control.Exception
 import Data.Array.Unboxed
 import Data.Array.IArray
@@ -13,6 +15,7 @@
 import Time
 import SAXPY
 import DotP
+import Filter
 
 
 -- Auxilliary array functions
@@ -211,6 +214,27 @@
     {-# NOINLINE dotp_interp #-}
     dotp_interp arr1 arr2 () = Interp.run (dotp arr1 arr2)
 
+test_filter :: Int -> IO ()
+test_filter n
+  = do
+      putStrLn "== Filter"
+      putStrLn $ "Generating data (n = " ++ show n ++ ")..."
+      v_ref <- randomUVector n
+      v     <- convertUVector v_ref
+      putStrLn "Running reference code..."
+      ref_result <- timeUVector $ filter_ref' (< 0) v_ref
+      putStrLn "Running Accelerate code..."
+      result <- timeVector $ filter_interp (Acc.<* Acc.constant 0) (Acc.use v)
+      putStrLn "Validating result..."
+      validateFloats ref_result result
+  where
+    -- idiom with NOINLINE and extra parameter needed to prevent optimisations
+    -- from sharing results over multiple runs
+    {-# NOINLINE filter_ref' #-}
+    filter_ref' p arr () = filter_ref p arr
+    {-# NOINLINE filter_interp #-}
+    filter_interp p arr () = Interp.run (filter p arr)
+
 main :: IO ()
 main
   = do
@@ -219,3 +243,4 @@
       
       test_saxpy 100000
       test_dotp  100000
+      test_filter 2000
diff --git a/examples/simple/Makefile b/examples/simple/Makefile
--- a/examples/simple/Makefile
+++ b/examples/simple/Makefile
@@ -4,9 +4,10 @@
 	ghc $(HCFLAGS) -c Time.hs
 	ghc $(HCFLAGS) -c SAXPY.hs
 	ghc $(HCFLAGS) -c DotP.hs
+	ghc $(HCFLAGS) -c Filter.hs
 	ghc $(HCFLAGS) -c Main.hs
-	ghc $(HCFLAGS) -o test Main.o Time.o SAXPY.o DotP.o
+	ghc $(HCFLAGS) -o test Main.o Time.o SAXPY.o DotP.o Filter.o
 
 clean:
-	rm -f *.o *.hi time
+	rm -f *.o *.hi test
 	
