concat :: (A.Slice sh,Shape sh,Elt a)
       => A.Acc (Array (sh A.:. Int) a) -> A.Acc (Array (sh A.:. Int) a) -> TuneM (A.Acc (Array (sh A.:. Int) a))
concat xs ys = return $ A.generate gsh f
    where (sh1 A.:. n) = A.unlift $ A.shape xs
          (sh2 A.:. m) = A.unlift $ A.shape ys
          gsh          = A.lift $ (A.intersect sh1 sh2) A.:. (n + m)
          f ix         = ((A.indexHead ix) A.<* n) A.?
                         (xs A.! ix,
                          ys A.! (A.lift ((A.indexTail ix) A.:. ((A.indexHead ix) - n))))
concat :: (A.Slice sh,Shape sh,Elt a)
       => A.Acc (Array (sh A.:. Int) a) -> A.Acc (Array (sh A.:. Int) a) -> TuneM (A.Acc (Array (sh A.:. Int) a))
concat xs ys = return $ A.generate gsh f
    where (sh1 A.:. n) = A.unlift $ A.shape xs
          (sh2 A.:. m) = A.unlift $ A.shape ys
          gsh          = A.lift $ (A.intersect sh1 sh2) A.:. (n + m)
          f ix         = ((A.indexHead ix) A.<* n) A.?
                         (xs A.! ix,
                          ys A.! (A.lift ((A.indexTail ix) A.:. ((A.indexHead ix) - n))))
concat xs ys = return $ A.generate gsh f
    where (sh1 A.:. n) = A.unlift $ A.shape xs
          (sh2 A.:. m) = A.unlift $ A.shape ys
          gsh          = A.lift $ (A.intersect sh1 sh2) A.:. (n + m)
          f ix         = ((A.indexHead ix) A.<* n) A.?
                         (xs A.! ix,
                          ys A.! (A.lift ((A.indexTail ix) A.:. ((A.indexHead ix) - n))))