content: {-# LANGUAGE GADTs               #-}
  {-# LANGUAGE PatternGuards       #-}
  {-# LANGUAGE RankNTypes          #-}
  {-# LANGUAGE ScopedTypeVariables #-}
  {-# LANGUAGE StandaloneDeriving  #-}
  {-# LANGUAGE TypeOperators       #-}
  {-# OPTIONS_HADDOCK hide #-}
  
  -- Discriminate binary functions that commute, and if so return the operands in
  -- a stable ordering such that matching recognises expressions modulo
  -- commutativity.
  --
  commutes
      :: forall acc env aenv a r.
         HashAcc acc
      -> PrimFun (a -> r)
      -> PreOpenExp acc env aenv a
      -> Maybe (PreOpenExp acc env aenv a)
  commutes h f x = case f of
    PrimAdd _     -> Just (swizzle x)
    PrimMul _     -> Just (swizzle x)
    PrimBAnd _    -> Just (swizzle x)
    PrimBOr _     -> Just (swizzle x)
    PrimBXor _    -> Just (swizzle x)
    PrimEq _      -> Just (swizzle x)
    PrimNEq _     -> Just (swizzle x)
    PrimMax _     -> Just (swizzle x)
    PrimMin _     -> Just (swizzle x)
    PrimLAnd      -> Just (swizzle x)
    PrimLOr       -> Just (swizzle x)
    _             -> Nothing
    where
      swizzle :: PreOpenExp acc env aenv (a',a') -> PreOpenExp acc env aenv (a',a')
      swizzle exp
        | Tuple (NilTup `SnocTup` a `SnocTup` b)  <- exp
        , hashPreOpenExp h a > hashPreOpenExp h b = Tuple (NilTup `SnocTup` b `SnocTup` a)
        --
        | otherwise                               = exp
  