diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,27 @@
+Copyright (c) Henning Thielemann 2014
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+3. Neither the name of the author nor the names of his contributors
+   may be used to endorse or promote products derived from this software
+   without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGE.
diff --git a/Setup.lhs b/Setup.lhs
new file mode 100644
--- /dev/null
+++ b/Setup.lhs
@@ -0,0 +1,3 @@
+#! /usr/bin/env runhaskell
+> import Distribution.Simple
+> main = defaultMain
diff --git a/accelerate-utility.cabal b/accelerate-utility.cabal
new file mode 100644
--- /dev/null
+++ b/accelerate-utility.cabal
@@ -0,0 +1,40 @@
+Name:             accelerate-utility
+Version:          0.0
+License:          BSD3
+License-File:     LICENSE
+Author:           Henning Thielemann <haskell@henning-thielemann.de>
+Maintainer:       Henning Thielemann <haskell@henning-thielemann.de>
+Homepage:         http://code.haskell.org/~thielema/accelerate-utility/
+Category:         Parallelism
+Synopsis:         Utility functions for the Accelerate framework
+Description:
+  Several utility functions on top of the Accelerate framework.
+  The functions simplify working with indices and lifting and unlifting.
+Tested-With:      GHC==7.8.3
+Cabal-Version:    >=1.14
+Build-Type:       Simple
+
+Source-Repository this
+  Tag:         0.0
+  Type:        darcs
+  Location:    http://code.haskell.org/~thielema/accelerate-utility/
+
+Source-Repository head
+  Type:        darcs
+  Location:    http://code.haskell.org/~thielema/accelerate-utility/
+
+Library
+  Build-Depends:
+    accelerate >=0.15 && <0.16,
+    utility-ht >=0.0.8 && <0.1,
+    base >=4.5 && <4.8
+
+  GHC-Options:      -Wall -fwarn-missing-import-lists
+  Hs-Source-Dirs:   src
+  Default-Language: Haskell98
+  Exposed-Modules:
+    Data.Array.Accelerate.Utility.Lift.Acc
+    Data.Array.Accelerate.Utility.Lift.Exp
+    Data.Array.Accelerate.Utility.Lift.Run
+    Data.Array.Accelerate.Utility.Loop
+    Data.Array.Accelerate.Utility.Arrange
diff --git a/src/Data/Array/Accelerate/Utility/Arrange.hs b/src/Data/Array/Accelerate/Utility/Arrange.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Array/Accelerate/Utility/Arrange.hs
@@ -0,0 +1,31 @@
+module Data.Array.Accelerate.Utility.Arrange (
+   mapWithIndex,
+   gather,
+   scatter,
+   ) where
+
+import qualified Data.Array.Accelerate as A
+import Data.Array.Accelerate (Acc, Array, Exp)
+
+
+mapWithIndex ::
+   (A.Shape sh, A.Elt a, A.Elt b) =>
+   (Exp sh -> Exp a -> Exp b) ->
+   Acc (Array sh a) -> Acc (Array sh b)
+mapWithIndex f xs =
+   A.zipWith f (A.generate (A.shape xs) id) xs
+
+
+gather ::
+   (A.Shape ix, A.Shape ix', A.Elt ix', A.Elt a) =>
+   Acc (Array ix ix') -> Acc (Array ix' a) -> Acc (Array ix a)
+gather indices xs =
+   A.map (xs A.!) indices
+
+scatter ::
+   (A.Shape ix, A.Shape ix', A.Elt ix', A.Elt a) =>
+   (Exp a -> Exp a -> Exp a) ->
+   Acc (Array ix ix') -> Acc (Array ix' a) ->
+   Acc (Array ix a) -> Acc (Array ix' a)
+scatter f indices deflt xs =
+   A.permute f deflt (indices A.!) xs
diff --git a/src/Data/Array/Accelerate/Utility/Lift/Acc.hs b/src/Data/Array/Accelerate/Utility/Lift/Acc.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Array/Accelerate/Utility/Lift/Acc.hs
@@ -0,0 +1,145 @@
+{-# LANGUAGE TypeFamilies #-}
+{-# LANGUAGE TypeOperators #-}
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE FlexibleContexts #-}
+module Data.Array.Accelerate.Utility.Lift.Acc (
+   Unlift,
+   Unlifted,
+   Tuple,
+   unlift,
+   modify,
+   modify2,
+   modify3,
+   modify4,
+   Acc(Acc), acc,
+   Exp(Exp), expr,
+   unliftPair,
+   unliftTriple,
+   unliftQuadruple,
+   mapFst,
+   mapSnd,
+   singleton,
+   the,
+   ) where
+
+import qualified Data.Array.Accelerate as A
+
+import qualified Data.Tuple.HT as Tuple
+import Data.Tuple.HT (mapTriple)
+
+
+class (A.Arrays (Tuple pattern)) => Unlift pattern where
+   type Unlifted pattern
+   type Tuple pattern
+   unlift :: pattern -> A.Acc (Tuple pattern) -> Unlifted pattern
+
+modify ::
+   (A.Lift A.Acc a, Unlift pattern) =>
+   pattern ->
+   (Unlifted pattern -> a) ->
+   A.Acc (Tuple pattern) -> A.Acc (A.Plain a)
+modify p f = A.lift . f . unlift p
+
+modify2 ::
+   (A.Lift A.Acc a, Unlift patternA, Unlift patternB) =>
+   patternA ->
+   patternB ->
+   (Unlifted patternA -> Unlifted patternB -> a) ->
+   A.Acc (Tuple patternA) -> A.Acc (Tuple patternB) -> A.Acc (A.Plain a)
+modify2 pa pb f a b = A.lift $ f (unlift pa a) (unlift pb b)
+
+modify3 ::
+   (A.Lift A.Acc a, Unlift patternA, Unlift patternB, Unlift patternC) =>
+   patternA ->
+   patternB ->
+   patternC ->
+   (Unlifted patternA -> Unlifted patternB -> Unlifted patternC -> a) ->
+   A.Acc (Tuple patternA) -> A.Acc (Tuple patternB) ->
+   A.Acc (Tuple patternC) -> A.Acc (A.Plain a)
+modify3 pa pb pc f a b c =
+   A.lift $ f (unlift pa a) (unlift pb b) (unlift pc c)
+
+modify4 ::
+   (A.Lift A.Acc a,
+    Unlift patternA, Unlift patternB, Unlift patternC, Unlift patternD) =>
+   patternA ->
+   patternB ->
+   patternC ->
+   patternD ->
+   (Unlifted patternA -> Unlifted patternB ->
+    Unlifted patternC -> Unlifted patternD -> a) ->
+   A.Acc (Tuple patternA) -> A.Acc (Tuple patternB) ->
+   A.Acc (Tuple patternC) -> A.Acc (Tuple patternD) -> A.Acc (A.Plain a)
+modify4 pa pb pc pd f a b c d =
+   A.lift $ f (unlift pa a) (unlift pb b) (unlift pc c) (unlift pd d)
+
+
+instance (A.Arrays a) => Unlift (Acc a) where
+   type Unlifted (Acc a) = A.Acc a
+   type Tuple (Acc a) = a
+   unlift _ = id
+
+data Acc a = Acc
+
+acc :: Acc a
+acc = Acc
+
+
+instance (A.Elt a) => Unlift (Exp a) where
+   type Unlifted (Exp a) = A.Exp a
+   type Tuple (Exp a) = A.Scalar a
+   unlift _ = A.the
+
+data Exp e = Exp
+
+expr :: Exp e
+expr = Exp
+
+
+-- | like 'A.unit' in the 'Acc' environment
+singleton :: (A.Elt e) => e -> A.Scalar e
+singleton x = A.fromList A.Z [x]
+
+-- | like 'A.the' in the 'Acc' environment
+the :: (A.Elt e) => A.Scalar e -> e
+the arr = A.indexArray arr A.Z
+
+
+instance (Unlift pa, Unlift pb) => Unlift (pa,pb) where
+   type Unlifted (pa,pb) = (Unlifted pa, Unlifted pb)
+   type Tuple (pa,pb) = (Tuple pa, Tuple pb)
+   unlift (pa,pb) ab =
+      (unlift pa $ A.afst ab, unlift pb $ A.asnd ab)
+
+instance
+   (Unlift pa, Unlift pb, Unlift pc) =>
+      Unlift (pa,pb,pc) where
+   type Unlifted (pa,pb,pc) = (Unlifted pa, Unlifted pb, Unlifted pc)
+   type Tuple (pa,pb,pc) = (Tuple pa, Tuple pb, Tuple pc)
+   unlift (pa,pb,pc) =
+      mapTriple (unlift pa, unlift pb, unlift pc) . A.unlift
+
+
+
+unliftPair :: (A.Arrays a, A.Arrays b) => A.Acc (a,b) -> (A.Acc a, A.Acc b)
+unliftPair = A.unlift
+
+unliftTriple ::
+   (A.Arrays a, A.Arrays b, A.Arrays c) => A.Acc (a,b,c) -> (A.Acc a, A.Acc b, A.Acc c)
+unliftTriple = A.unlift
+
+unliftQuadruple ::
+   (A.Arrays a, A.Arrays b, A.Arrays c, A.Arrays d) =>
+   A.Acc (a,b,c,d) -> (A.Acc a, A.Acc b, A.Acc c, A.Acc d)
+unliftQuadruple = A.unlift
+
+
+mapFst ::
+   (A.Arrays a, A.Arrays b, A.Arrays c) =>
+   (A.Acc a -> A.Acc b) -> A.Acc (a,c) -> A.Acc (b,c)
+mapFst f = modify (acc,acc) $ Tuple.mapFst f
+
+mapSnd ::
+   (A.Arrays a, A.Arrays b, A.Arrays c) =>
+   (A.Acc b -> A.Acc c) -> A.Acc (a,b) -> A.Acc (a,c)
+mapSnd f = modify (acc,acc) $ Tuple.mapSnd f
diff --git a/src/Data/Array/Accelerate/Utility/Lift/Exp.hs b/src/Data/Array/Accelerate/Utility/Lift/Exp.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Array/Accelerate/Utility/Lift/Exp.hs
@@ -0,0 +1,159 @@
+{-# LANGUAGE TypeFamilies #-}
+{-# LANGUAGE TypeOperators #-}
+{-# LANGUAGE FlexibleContexts #-}
+module Data.Array.Accelerate.Utility.Lift.Exp (
+   Unlift,
+   Unlifted,
+   Tuple,
+   unlift,
+   modify,
+   modify2,
+   modify3,
+   modify4,
+   Atom(Atom), atom,
+   unliftPair,
+   unliftTriple,
+   unliftQuadruple,
+   asExp,
+   mapFst,
+   mapSnd,
+   fst3,
+   snd3,
+   thd3,
+   indexCons,
+   ) where
+
+import qualified Data.Array.Accelerate as A
+import Data.Array.Accelerate (Exp, (:.)((:.)))
+
+import qualified Data.Tuple.HT as Tuple
+import Data.Tuple.HT (mapTriple)
+
+
+class
+   (A.Elt (Tuple pattern), A.Plain (Unlifted pattern) ~ Tuple pattern) =>
+      Unlift pattern where
+   type Unlifted pattern
+   type Tuple pattern
+   unlift :: pattern -> Exp (Tuple pattern) -> Unlifted pattern
+
+modify ::
+   (A.Lift Exp a, Unlift pattern) =>
+   pattern ->
+   (Unlifted pattern -> a) ->
+   Exp (Tuple pattern) -> Exp (A.Plain a)
+modify p f = A.lift . f . unlift p
+
+modify2 ::
+   (A.Lift Exp a, Unlift patternA, Unlift patternB) =>
+   patternA ->
+   patternB ->
+   (Unlifted patternA -> Unlifted patternB -> a) ->
+   Exp (Tuple patternA) -> Exp (Tuple patternB) -> Exp (A.Plain a)
+modify2 pa pb f a b = A.lift $ f (unlift pa a) (unlift pb b)
+
+modify3 ::
+   (A.Lift Exp a, Unlift patternA, Unlift patternB, Unlift patternC) =>
+   patternA ->
+   patternB ->
+   patternC ->
+   (Unlifted patternA -> Unlifted patternB -> Unlifted patternC -> a) ->
+   Exp (Tuple patternA) -> Exp (Tuple patternB) ->
+   Exp (Tuple patternC) -> Exp (A.Plain a)
+modify3 pa pb pc f a b c =
+   A.lift $ f (unlift pa a) (unlift pb b) (unlift pc c)
+
+modify4 ::
+   (A.Lift Exp a,
+    Unlift patternA, Unlift patternB, Unlift patternC, Unlift patternD) =>
+   patternA ->
+   patternB ->
+   patternC ->
+   patternD ->
+   (Unlifted patternA -> Unlifted patternB ->
+    Unlifted patternC -> Unlifted patternD -> a) ->
+   Exp (Tuple patternA) -> Exp (Tuple patternB) ->
+   Exp (Tuple patternC) -> Exp (Tuple patternD) -> Exp (A.Plain a)
+modify4 pa pb pc pd f a b c d =
+   A.lift $ f (unlift pa a) (unlift pb b) (unlift pc c) (unlift pd d)
+
+
+instance (A.Elt a) => Unlift (Atom a) where
+   type Unlifted (Atom a) = Exp a
+   type Tuple (Atom a) = a
+   unlift _ = id
+
+data Atom a = Atom
+
+atom :: Atom a
+atom = Atom
+
+
+instance (Unlift pa, Unlift pb) => Unlift (pa,pb) where
+   type Unlifted (pa,pb) = (Unlifted pa, Unlifted pb)
+   type Tuple (pa,pb) = (Tuple pa, Tuple pb)
+   unlift (pa,pb) ab =
+      (unlift pa $ A.fst ab, unlift pb $ A.snd ab)
+
+instance
+   (Unlift pa, Unlift pb, Unlift pc) =>
+      Unlift (pa,pb,pc) where
+   type Unlifted (pa,pb,pc) = (Unlifted pa, Unlifted pb, Unlifted pc)
+   type Tuple (pa,pb,pc) = (Tuple pa, Tuple pb, Tuple pc)
+   unlift (pa,pb,pc) =
+      mapTriple (unlift pa, unlift pb, unlift pc) . A.unlift
+
+
+instance (Unlift pa, A.Slice (Tuple pa), int ~ Atom Int) => Unlift (pa :. int) where
+   type Unlifted (pa :. int) = Unlifted pa :. Exp Int
+   type Tuple (pa :. int) = Tuple pa :. Int
+   unlift (pa:.pb) ab =
+      (unlift pa $ A.indexTail ab) :. (unlift pb $ A.indexHead ab)
+
+
+unliftPair :: (A.Elt a, A.Elt b) => Exp (a,b) -> (Exp a, Exp b)
+unliftPair = A.unlift
+
+unliftTriple ::
+   (A.Elt a, A.Elt b, A.Elt c) => Exp (a,b,c) -> (Exp a, Exp b, Exp c)
+unliftTriple = A.unlift
+
+unliftQuadruple ::
+   (A.Elt a, A.Elt b, A.Elt c, A.Elt d) =>
+   Exp (a,b,c,d) -> (Exp a, Exp b, Exp c, Exp d)
+unliftQuadruple = A.unlift
+
+asExp :: Exp a -> Exp a
+asExp = id
+
+mapFst ::
+   (A.Elt a, A.Elt b, A.Elt c) =>
+   (Exp a -> Exp b) -> Exp (a,c) -> Exp (b,c)
+mapFst f = modify (atom,atom) $ \(a,c) -> (f a, c)
+
+mapSnd ::
+   (A.Elt a, A.Elt b, A.Elt c) =>
+   (Exp b -> Exp c) -> Exp (a,b) -> Exp (a,c)
+mapSnd f = modify (atom,atom) $ \(a,b) -> (a, f b)
+
+
+fst3 ::
+   (A.Elt a, A.Elt b, A.Elt c) =>
+   Exp (a,b,c) -> Exp a
+fst3 = modify (atom,atom,atom) Tuple.fst3
+
+snd3 ::
+   (A.Elt a, A.Elt b, A.Elt c) =>
+   Exp (a,b,c) -> Exp b
+snd3 = modify (atom,atom,atom) Tuple.snd3
+
+thd3 ::
+   (A.Elt a, A.Elt b, A.Elt c) =>
+   Exp (a,b,c) -> Exp c
+thd3 = modify (atom,atom,atom) Tuple.thd3
+
+
+
+indexCons ::
+   (A.Slice ix) => Exp ix -> Exp Int -> Exp (ix :. Int)
+indexCons ix n = A.lift $ ix:.n
diff --git a/src/Data/Array/Accelerate/Utility/Lift/Run.hs b/src/Data/Array/Accelerate/Utility/Lift/Run.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Array/Accelerate/Utility/Lift/Run.hs
@@ -0,0 +1,166 @@
+{-# LANGUAGE TypeFamilies #-}
+{-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE UndecidableInstances #-}
+{-# LANGUAGE TypeOperators #-}
+{- |
+Simplify running @accelerate@ functions
+with multiple curried array and expression arguments.
+-}
+module Data.Array.Accelerate.Utility.Lift.Run (
+   C(..), with,
+   Argument(..),
+   ) where
+
+import qualified Data.Array.Accelerate.Utility.Lift.Acc as Acc
+
+import qualified Data.Array.Accelerate as A
+import Data.Array.Accelerate (Acc, Exp, Z, (:.))
+
+import Data.Tuple.HT (mapPair, mapTriple)
+
+
+merge ::
+   (A.Arrays a, A.Arrays packed) =>
+   (Acc packed -> b) ->
+   (Acc a -> b -> c) -> (Acc (a,packed) -> c)
+merge unpack f arr = f (A.afst arr) (unpack $ A.asnd arr)
+
+_mergeAcc ::
+   (A.Arrays a, A.Arrays b) =>
+   (Acc a -> Acc b -> c) -> (Acc (a,b) -> c)
+_mergeAcc f arr = f (A.afst arr) (A.asnd arr)
+
+_mergeExp ::
+   (A.Elt a, A.Arrays b) =>
+   (Exp a -> Acc b -> c) -> (Acc (A.Scalar a, b) -> c)
+_mergeExp f arr = f (A.the $ A.afst arr) (A.asnd arr)
+
+_mergeExpR ::
+   (A.Arrays a, A.Elt b) =>
+   (Acc a -> Exp b -> c) -> (Acc (a, A.Scalar b) -> c)
+_mergeExpR f arr = f (A.afst arr) (A.the $ A.asnd arr)
+
+
+split ::
+   (A.Arrays a, A.Arrays packed) =>
+   (unpacked -> packed) ->
+   ((a, packed) -> c) -> (a -> unpacked -> c)
+split pack f a b = f (a, pack b)
+
+_splitAcc :: ((a,b) -> c) -> (a -> b -> c)
+_splitAcc = curry
+
+_splitExp :: (A.Elt a) => ((A.Scalar a, b) -> c) -> (a -> b -> c)
+_splitExp f a b = f (Acc.singleton a, b)
+
+_splitExpR :: (A.Elt b) => ((a, A.Scalar b) -> c) -> (a -> b -> c)
+_splitExpR f a b = f (a, Acc.singleton b)
+
+
+
+{-
+(Acc ((a,b),c)) -> Acc d) -> (((a,b),c) -> d)
+(Acc (a,b) -> Acc c -> Acc d) -> ((a,b) -> c -> d)
+(Acc a -> Acc b -> Acc c -> Acc d) -> (a -> b -> c -> d)
+-}
+class C f where
+   type Arguments a f
+   type Result f
+   type Plain f
+   with1 ::
+      (A.Arrays a) =>
+      ((Acc (Arguments a f) -> Acc (Result f)) ->
+       ((Arguments a f) -> Result f)) ->
+      (Acc a -> f) -> a -> Plain f
+
+with ::
+   (C f) =>
+   ((Acc (Arguments () f) -> Acc (Result f)) ->
+    ((Arguments () f) -> Result f)) ->
+   f -> Plain f
+with run f = with1 run (const f) ()
+
+
+instance C (Acc r) where
+   type Arguments a (Acc r) = a
+   type Result (Acc r) = r
+   type Plain (Acc r) = r
+   with1 run f = run f
+
+instance
+   (A.Lift Acc r, A.Arrays (A.Plain r),
+    A.Lift Acc s, A.Arrays (A.Plain s)) =>
+      C (r,s) where
+   type Arguments a (r,s) = a
+   type Result (r,s) = (A.Plain r, A.Plain s)
+   type Plain (r,s) = (A.Plain r, A.Plain s)
+   with1 run f = run (A.lift . f)
+
+instance
+   (A.Lift Acc r, A.Arrays (A.Plain r),
+    A.Lift Acc s, A.Arrays (A.Plain s),
+    A.Lift Acc t, A.Arrays (A.Plain t)) =>
+      C (r,s,t) where
+   type Arguments a (r,s,t) = a
+   type Result (r,s,t) = (A.Plain r, A.Plain s, A.Plain t)
+   type Plain (r,s,t) = (A.Plain r, A.Plain s, A.Plain t)
+   with1 run f = run (A.lift . f)
+
+
+
+instance (Argument arg, C f) => C (arg -> f) where
+   type Arguments a (arg -> f) = Arguments (a, Packed arg) f
+   type Result (arg -> f) = Result f
+   type Plain (arg -> f) = Unpacked arg -> Plain f
+   with1 run f =
+      case tunnel of
+         (pack, unpack) ->
+            split pack (with1 run $ merge unpack f)
+
+
+class (A.Arrays (Packed a)) => Argument a where
+   type Packed a
+   type Unpacked a
+   tunnel :: (Unpacked a -> Packed a, Acc (Packed a) -> a)
+
+instance (A.Arrays a) => Argument (Acc a) where
+   type Packed (Acc a) = a
+   type Unpacked (Acc a) = a
+   tunnel = (id, id)
+
+instance (A.Elt a) => Argument (Exp a) where
+   type Packed (Exp a) = A.Scalar a
+   type Unpacked (Exp a) = a
+   tunnel = (Acc.singleton, A.the)
+
+instance (Argument a, Argument b) => Argument (a,b) where
+   type Packed (a,b) = (Packed a, Packed b)
+   type Unpacked (a,b) = (Unpacked a, Unpacked b)
+   tunnel =
+      case (tunnel, tunnel) of
+         ((packA, unpackA), (packB, unpackB)) ->
+            (mapPair (packA,packB),
+             mapPair (unpackA,unpackB) . A.unlift)
+
+instance (Argument a, Argument b, Argument c) => Argument (a,b,c) where
+   type Packed (a,b,c) = (Packed a, Packed b, Packed c)
+   type Unpacked (a,b,c) = (Unpacked a, Unpacked b, Unpacked c)
+   tunnel =
+      case (tunnel, tunnel, tunnel) of
+         ((packA, unpackA), (packB, unpackB), (packC, unpackC)) ->
+            (mapTriple (packA,packB,packC),
+             mapTriple (unpackA,unpackB,unpackC) . A.unlift)
+
+
+instance Argument Z where
+   type Packed Z = A.Scalar Z
+   type Unpacked Z = Z
+   tunnel = (Acc.singleton, A.unlift . A.the)
+
+instance
+   (A.Unlift Exp a, A.Lift Exp a, A.Slice (A.Plain a), b ~ Exp Int) =>
+      Argument (a:.b) where
+   type Packed (a:.b) = A.Scalar (A.Plain a :. Int)
+   type Unpacked (a:.b) = A.Plain a :. Int
+   tunnel = (Acc.singleton, A.unlift . A.the)
+
diff --git a/src/Data/Array/Accelerate/Utility/Loop.hs b/src/Data/Array/Accelerate/Utility/Loop.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Array/Accelerate/Utility/Loop.hs
@@ -0,0 +1,47 @@
+module Data.Array.Accelerate.Utility.Loop (
+   nest,
+   nestLog2,
+   ) where
+
+import qualified Data.Array.Accelerate as A
+import Data.Array.Accelerate (Acc, Exp)
+
+
+
+nest, _nest ::
+   (A.Arrays a) =>
+   Exp Int -> (Acc a -> Acc a) -> Acc a -> Acc a
+nest n0 f x0 =
+   A.asnd $
+   A.awhile
+      (A.map (A.>* 0) . A.afst)
+      (A.lift . (\(n, x) -> (A.map (subtract 1) n, f x)) . A.unlift)
+      (A.lift (A.unit n0, x0))
+
+_nest n0 f x0 =
+   A.asnd $
+   A.awhile
+      (A.unit . (A.>* 0) . A.the . A.afst)
+      (A.lift . (\(n, x) -> (A.unit $ A.the n - 1, f x)) . A.unlift)
+      (A.lift (A.unit n0, x0))
+
+
+nestLog2, _nestLog2 ::
+   (A.Arrays a) =>
+   Exp Int -> (Acc a -> Acc a) -> Acc a -> Acc a
+nestLog2 n0 f x0 =
+   A.asnd $
+   A.awhile
+      (A.map (A.>* 1) . A.afst)
+      (A.lift . (\(n, x) -> (A.map (flip div 2 . (1+)) n, f x)) . A.unlift)
+      (A.lift (A.unit n0, x0))
+
+{-
+This is an infinite loop,
+because A.acond always has to generate code for both branches.
+-}
+_nestLog2 n0 f x0 =
+   let go n x =
+          A.acond (n A.<=* 1) x $
+          go (div (n+1) 2) (f x)
+   in  go n0 x0
